Compare commits
13 Commits
auth@0.43.
...
@nhost/das
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f2b93d44b | ||
|
|
1aeef26ec6 | ||
|
|
749bb4e637 | ||
|
|
accabc83f7 | ||
|
|
8c127d7b6b | ||
|
|
f9c614ef99 | ||
|
|
1d183f7fc4 | ||
|
|
46e740f060 | ||
|
|
0d30ab4eec | ||
|
|
d5fd3cb59c | ||
|
|
f36d360b9e | ||
|
|
61af5087fd | ||
|
|
7429d8ae3f |
@@ -3,6 +3,7 @@
|
|||||||
"$schema": "https://github.com/IBM/audit-ci/raw/main/docs/schema.json",
|
"$schema": "https://github.com/IBM/audit-ci/raw/main/docs/schema.json",
|
||||||
"moderate": true,
|
"moderate": true,
|
||||||
"allowlist": [
|
"allowlist": [
|
||||||
"GHSA-9965-vmph-33xx" // https://github.com/advisories/GHSA-9965-vmph-33xx Update package once have a fix
|
"GHSA-9965-vmph-33xx", // https://github.com/advisories/GHSA-9965-vmph-33xx Update package once have a fix
|
||||||
|
"GHSA-7mvr-c777-76hp" // https://github.com/advisories/GHSA-7mvr-c777-76hp Update package once Nix side is also updated
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [cli@1.34.2] - 2025-10-20
|
||||||
|
|
||||||
|
### ⚙️ Miscellaneous Tasks
|
||||||
|
|
||||||
|
- *(cli)* Minor fix to download script when specifying version (#3602)
|
||||||
|
- *(cli)* Update schema (#3613)
|
||||||
|
|
||||||
## [cli@1.34.1] - 2025-10-13
|
## [cli@1.34.1] - 2025-10-13
|
||||||
|
|
||||||
### 🐛 Bug Fixes
|
### 🐛 Bug Fixes
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ func auth( //nolint:funlen
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
"00000000-0000-0000-0000-000000000000",
|
"00000000-0000-0000-0000-000000000000",
|
||||||
|
"5181f67e2844e4b60d571fa346cac9c37fc00d1ff519212eae6cead138e639ba",
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get hasura env vars: %w", err)
|
return nil, fmt.Errorf("failed to get hasura env vars: %w", err)
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ func expectedAuth() *Service {
|
|||||||
"AUTH_DISABLE_SIGNUP": "false",
|
"AUTH_DISABLE_SIGNUP": "false",
|
||||||
"AUTH_EMAIL_PASSWORDLESS_ENABLED": "true",
|
"AUTH_EMAIL_PASSWORDLESS_ENABLED": "true",
|
||||||
"AUTH_EMAIL_SIGNIN_EMAIL_VERIFIED_REQUIRED": "true",
|
"AUTH_EMAIL_SIGNIN_EMAIL_VERIFIED_REQUIRED": "true",
|
||||||
|
"AUTH_ENCRYPTION_KEY": "5181f67e2844e4b60d571fa346cac9c37fc00d1ff519212eae6cead138e639ba",
|
||||||
"AUTH_GRAVATAR_DEFAULT": "gravatarDefault",
|
"AUTH_GRAVATAR_DEFAULT": "gravatarDefault",
|
||||||
"AUTH_GRAVATAR_ENABLED": "true",
|
"AUTH_GRAVATAR_ENABLED": "true",
|
||||||
"AUTH_GRAVATAR_RATING": "gravatarRating",
|
"AUTH_GRAVATAR_RATING": "gravatarRating",
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ import (
|
|||||||
#Hasura: {
|
#Hasura: {
|
||||||
// Version of hasura, you can see available versions in the URL below:
|
// Version of hasura, you can see available versions in the URL below:
|
||||||
// https://hub.docker.com/r/hasura/graphql-engine/tags
|
// https://hub.docker.com/r/hasura/graphql-engine/tags
|
||||||
version: string | *"v2.46.0-ce"
|
version: string | *"v2.48.5-ce"
|
||||||
|
|
||||||
// JWT Secrets configuration
|
// JWT Secrets configuration
|
||||||
jwtSecrets: [#JWTSecret]
|
jwtSecrets: [#JWTSecret]
|
||||||
@@ -223,7 +223,7 @@ import (
|
|||||||
// Releases:
|
// Releases:
|
||||||
//
|
//
|
||||||
// https://github.com/nhost/hasura-storage/releases
|
// https://github.com/nhost/hasura-storage/releases
|
||||||
version: string | *"0.7.2"
|
version: string | *"0.8.2"
|
||||||
|
|
||||||
// Networking (custom domains at the moment) are not allowed as we need to do further
|
// Networking (custom domains at the moment) are not allowed as we need to do further
|
||||||
// configurations in the CDN. We will enable it again in the future.
|
// configurations in the CDN. We will enable it again in the future.
|
||||||
@@ -311,7 +311,7 @@ import (
|
|||||||
// Releases:
|
// Releases:
|
||||||
//
|
//
|
||||||
// https://github.com/nhost/hasura-auth/releases
|
// https://github.com/nhost/hasura-auth/releases
|
||||||
version: string | *"0.38.1"
|
version: string | *"0.42.4"
|
||||||
|
|
||||||
// Resources for the service
|
// Resources for the service
|
||||||
resources?: #Resources
|
resources?: #Resources
|
||||||
@@ -651,6 +651,9 @@ import (
|
|||||||
iops: uint32 | *3000
|
iops: uint32 | *3000
|
||||||
tput: uint32 | *125
|
tput: uint32 | *125
|
||||||
}
|
}
|
||||||
|
|
||||||
|
encryptColumnKey?: string & =~"^[0-9a-fA-F]{64}$" // 32 bytes hex-encoded key
|
||||||
|
oldEncryptColumnKey?: string & =~"^[0-9a-fA-F]{64}$" // for key rotation
|
||||||
}
|
}
|
||||||
|
|
||||||
persistentVolumesEncrypted: bool | *false
|
persistentVolumesEncrypted: bool | *false
|
||||||
|
|||||||
@@ -70,18 +70,28 @@ type ConfigAIUpdateInput struct {
|
|||||||
WebhookSecret *string `json:"webhookSecret,omitempty"`
|
WebhookSecret *string `json:"webhookSecret,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configuration for auth service
|
||||||
|
// You can find more information about the configuration here:
|
||||||
|
// https://github.com/nhost/hasura-auth/blob/main/docs/environment-variables.md
|
||||||
type ConfigAuth struct {
|
type ConfigAuth struct {
|
||||||
ElevatedPrivileges *ConfigAuthElevatedPrivileges `json:"elevatedPrivileges,omitempty"`
|
ElevatedPrivileges *ConfigAuthElevatedPrivileges `json:"elevatedPrivileges,omitempty"`
|
||||||
Method *ConfigAuthMethod `json:"method,omitempty"`
|
Method *ConfigAuthMethod `json:"method,omitempty"`
|
||||||
Misc *ConfigAuthMisc `json:"misc,omitempty"`
|
Misc *ConfigAuthMisc `json:"misc,omitempty"`
|
||||||
RateLimit *ConfigAuthRateLimit `json:"rateLimit,omitempty"`
|
RateLimit *ConfigAuthRateLimit `json:"rateLimit,omitempty"`
|
||||||
Redirections *ConfigAuthRedirections `json:"redirections,omitempty"`
|
Redirections *ConfigAuthRedirections `json:"redirections,omitempty"`
|
||||||
Resources *ConfigResources `json:"resources,omitempty"`
|
// Resources for the service
|
||||||
Session *ConfigAuthSession `json:"session,omitempty"`
|
Resources *ConfigResources `json:"resources,omitempty"`
|
||||||
SignUp *ConfigAuthSignUp `json:"signUp,omitempty"`
|
Session *ConfigAuthSession `json:"session,omitempty"`
|
||||||
Totp *ConfigAuthTotp `json:"totp,omitempty"`
|
SignUp *ConfigAuthSignUp `json:"signUp,omitempty"`
|
||||||
User *ConfigAuthUser `json:"user,omitempty"`
|
Totp *ConfigAuthTotp `json:"totp,omitempty"`
|
||||||
Version *string `json:"version,omitempty"`
|
User *ConfigAuthUser `json:"user,omitempty"`
|
||||||
|
// Version of auth, you can see available versions in the URL below:
|
||||||
|
// https://hub.docker.com/r/nhost/hasura-auth/tags
|
||||||
|
//
|
||||||
|
// Releases:
|
||||||
|
//
|
||||||
|
// https://github.com/nhost/hasura-auth/releases
|
||||||
|
Version *string `json:"version,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigAuthElevatedPrivileges struct {
|
type ConfigAuthElevatedPrivileges struct {
|
||||||
@@ -111,9 +121,11 @@ type ConfigAuthMethodAnonymousUpdateInput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ConfigAuthMethodEmailPassword struct {
|
type ConfigAuthMethodEmailPassword struct {
|
||||||
EmailVerificationRequired *bool `json:"emailVerificationRequired,omitempty"`
|
EmailVerificationRequired *bool `json:"emailVerificationRequired,omitempty"`
|
||||||
HibpEnabled *bool `json:"hibpEnabled,omitempty"`
|
// Disabling email+password sign in is not implmented yet
|
||||||
PasswordMinLength *uint32 `json:"passwordMinLength,omitempty"`
|
// enabled: bool | *true
|
||||||
|
HibpEnabled *bool `json:"hibpEnabled,omitempty"`
|
||||||
|
PasswordMinLength *uint32 `json:"passwordMinLength,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigAuthMethodEmailPasswordUpdateInput struct {
|
type ConfigAuthMethodEmailPasswordUpdateInput struct {
|
||||||
@@ -335,8 +347,10 @@ type ConfigAuthRateLimitUpdateInput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ConfigAuthRedirections struct {
|
type ConfigAuthRedirections struct {
|
||||||
|
// AUTH_ACCESS_CONTROL_ALLOWED_REDIRECT_URLS
|
||||||
AllowedUrls []string `json:"allowedUrls,omitempty"`
|
AllowedUrls []string `json:"allowedUrls,omitempty"`
|
||||||
ClientURL *string `json:"clientUrl,omitempty"`
|
// AUTH_CLIENT_URL
|
||||||
|
ClientURL *string `json:"clientUrl,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigAuthRedirectionsUpdateInput struct {
|
type ConfigAuthRedirectionsUpdateInput struct {
|
||||||
@@ -350,8 +364,10 @@ type ConfigAuthSession struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ConfigAuthSessionAccessToken struct {
|
type ConfigAuthSessionAccessToken struct {
|
||||||
|
// AUTH_JWT_CUSTOM_CLAIMS
|
||||||
CustomClaims []*ConfigAuthsessionaccessTokenCustomClaims `json:"customClaims,omitempty"`
|
CustomClaims []*ConfigAuthsessionaccessTokenCustomClaims `json:"customClaims,omitempty"`
|
||||||
ExpiresIn *uint32 `json:"expiresIn,omitempty"`
|
// AUTH_ACCESS_TOKEN_EXPIRES_IN
|
||||||
|
ExpiresIn *uint32 `json:"expiresIn,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigAuthSessionAccessTokenUpdateInput struct {
|
type ConfigAuthSessionAccessTokenUpdateInput struct {
|
||||||
@@ -360,6 +376,7 @@ type ConfigAuthSessionAccessTokenUpdateInput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ConfigAuthSessionRefreshToken struct {
|
type ConfigAuthSessionRefreshToken struct {
|
||||||
|
// AUTH_REFRESH_TOKEN_EXPIRES_IN
|
||||||
ExpiresIn *uint32 `json:"expiresIn,omitempty"`
|
ExpiresIn *uint32 `json:"expiresIn,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,9 +390,11 @@ type ConfigAuthSessionUpdateInput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ConfigAuthSignUp struct {
|
type ConfigAuthSignUp struct {
|
||||||
DisableNewUsers *bool `json:"disableNewUsers,omitempty"`
|
// AUTH_DISABLE_NEW_USERS
|
||||||
Enabled *bool `json:"enabled,omitempty"`
|
DisableNewUsers *bool `json:"disableNewUsers,omitempty"`
|
||||||
Turnstile *ConfigAuthSignUpTurnstile `json:"turnstile,omitempty"`
|
// Inverse of AUTH_DISABLE_SIGNUP
|
||||||
|
Enabled *bool `json:"enabled,omitempty"`
|
||||||
|
Turnstile *ConfigAuthSignUpTurnstile `json:"turnstile,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigAuthSignUpTurnstile struct {
|
type ConfigAuthSignUpTurnstile struct {
|
||||||
@@ -425,12 +444,16 @@ type ConfigAuthUser struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ConfigAuthUserEmail struct {
|
type ConfigAuthUserEmail struct {
|
||||||
|
// AUTH_ACCESS_CONTROL_ALLOWED_EMAILS
|
||||||
Allowed []string `json:"allowed,omitempty"`
|
Allowed []string `json:"allowed,omitempty"`
|
||||||
|
// AUTH_ACCESS_CONTROL_BLOCKED_EMAILS
|
||||||
Blocked []string `json:"blocked,omitempty"`
|
Blocked []string `json:"blocked,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigAuthUserEmailDomains struct {
|
type ConfigAuthUserEmailDomains struct {
|
||||||
|
// AUTH_ACCESS_CONTROL_ALLOWED_EMAIL_DOMAINS
|
||||||
Allowed []string `json:"allowed,omitempty"`
|
Allowed []string `json:"allowed,omitempty"`
|
||||||
|
// AUTH_ACCESS_CONTROL_BLOCKED_EMAIL_DOMAINS
|
||||||
Blocked []string `json:"blocked,omitempty"`
|
Blocked []string `json:"blocked,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,6 +469,7 @@ type ConfigAuthUserEmailUpdateInput struct {
|
|||||||
|
|
||||||
type ConfigAuthUserGravatar struct {
|
type ConfigAuthUserGravatar struct {
|
||||||
Default *string `json:"default,omitempty"`
|
Default *string `json:"default,omitempty"`
|
||||||
|
// AUTH_GRAVATAR_ENABLED
|
||||||
Enabled *bool `json:"enabled,omitempty"`
|
Enabled *bool `json:"enabled,omitempty"`
|
||||||
Rating *string `json:"rating,omitempty"`
|
Rating *string `json:"rating,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -457,8 +481,10 @@ type ConfigAuthUserGravatarUpdateInput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ConfigAuthUserLocale struct {
|
type ConfigAuthUserLocale struct {
|
||||||
|
// AUTH_LOCALE_ALLOWED_LOCALES
|
||||||
Allowed []string `json:"allowed,omitempty"`
|
Allowed []string `json:"allowed,omitempty"`
|
||||||
Default *string `json:"default,omitempty"`
|
// AUTH_LOCALE_DEFAULT
|
||||||
|
Default *string `json:"default,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigAuthUserLocaleUpdateInput struct {
|
type ConfigAuthUserLocaleUpdateInput struct {
|
||||||
@@ -467,8 +493,10 @@ type ConfigAuthUserLocaleUpdateInput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ConfigAuthUserRoles struct {
|
type ConfigAuthUserRoles struct {
|
||||||
|
// AUTH_USER_DEFAULT_ALLOWED_ROLES
|
||||||
Allowed []string `json:"allowed,omitempty"`
|
Allowed []string `json:"allowed,omitempty"`
|
||||||
Default *string `json:"default,omitempty"`
|
// AUTH_USER_DEFAULT_ROLE
|
||||||
|
Default *string `json:"default,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigAuthUserRolesUpdateInput struct {
|
type ConfigAuthUserRolesUpdateInput struct {
|
||||||
@@ -484,6 +512,7 @@ type ConfigAuthUserUpdateInput struct {
|
|||||||
Roles *ConfigAuthUserRolesUpdateInput `json:"roles,omitempty"`
|
Roles *ConfigAuthUserRolesUpdateInput `json:"roles,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AUTH_JWT_CUSTOM_CLAIMS
|
||||||
type ConfigAuthsessionaccessTokenCustomClaims struct {
|
type ConfigAuthsessionaccessTokenCustomClaims struct {
|
||||||
Default *string `json:"default,omitempty"`
|
Default *string `json:"default,omitempty"`
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
@@ -522,8 +551,11 @@ type ConfigClaimMapUpdateInput struct {
|
|||||||
Value *string `json:"value,omitempty"`
|
Value *string `json:"value,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resource configuration for a service
|
||||||
type ConfigComputeResources struct {
|
type ConfigComputeResources struct {
|
||||||
CPU uint32 `json:"cpu"`
|
// milicpus, 1000 milicpus = 1 cpu
|
||||||
|
CPU uint32 `json:"cpu"`
|
||||||
|
// MiB: 128MiB to 30GiB
|
||||||
Memory uint32 `json:"memory"`
|
Memory uint32 `json:"memory"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -537,17 +569,28 @@ type ConfigComputeResourcesUpdateInput struct {
|
|||||||
Memory *uint32 `json:"memory,omitempty"`
|
Memory *uint32 `json:"memory,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// main entrypoint to the configuration
|
||||||
type ConfigConfig struct {
|
type ConfigConfig struct {
|
||||||
Ai *ConfigAi `json:"ai,omitempty"`
|
// Configuration for graphite service
|
||||||
Auth *ConfigAuth `json:"auth,omitempty"`
|
Ai *ConfigAi `json:"ai,omitempty"`
|
||||||
Functions *ConfigFunctions `json:"functions,omitempty"`
|
// Configuration for auth service
|
||||||
Global *ConfigGlobal `json:"global,omitempty"`
|
Auth *ConfigAuth `json:"auth,omitempty"`
|
||||||
Graphql *ConfigGraphql `json:"graphql,omitempty"`
|
// Configuration for functions service
|
||||||
Hasura *ConfigHasura `json:"hasura"`
|
Functions *ConfigFunctions `json:"functions,omitempty"`
|
||||||
|
// Global configuration that applies to all services
|
||||||
|
Global *ConfigGlobal `json:"global,omitempty"`
|
||||||
|
// Advanced configuration for GraphQL
|
||||||
|
Graphql *ConfigGraphql `json:"graphql,omitempty"`
|
||||||
|
// Configuration for hasura
|
||||||
|
Hasura *ConfigHasura `json:"hasura"`
|
||||||
|
// Configuration for observability service
|
||||||
Observability *ConfigObservability `json:"observability"`
|
Observability *ConfigObservability `json:"observability"`
|
||||||
Postgres *ConfigPostgres `json:"postgres"`
|
// Configuration for postgres service
|
||||||
Provider *ConfigProvider `json:"provider,omitempty"`
|
Postgres *ConfigPostgres `json:"postgres"`
|
||||||
Storage *ConfigStorage `json:"storage,omitempty"`
|
// Configuration for third party providers like SMTP, SMS, etc.
|
||||||
|
Provider *ConfigProvider `json:"provider,omitempty"`
|
||||||
|
// Configuration for storage service
|
||||||
|
Storage *ConfigStorage `json:"storage,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigConfigUpdateInput struct {
|
type ConfigConfigUpdateInput struct {
|
||||||
@@ -564,7 +607,8 @@ type ConfigConfigUpdateInput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ConfigEnvironmentVariable struct {
|
type ConfigEnvironmentVariable struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
// Value of the environment variable
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -578,6 +622,7 @@ type ConfigEnvironmentVariableUpdateInput struct {
|
|||||||
Value *string `json:"value,omitempty"`
|
Value *string `json:"value,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configuration for functions service
|
||||||
type ConfigFunctions struct {
|
type ConfigFunctions struct {
|
||||||
Node *ConfigFunctionsNode `json:"node,omitempty"`
|
Node *ConfigFunctionsNode `json:"node,omitempty"`
|
||||||
RateLimit *ConfigRateLimit `json:"rateLimit,omitempty"`
|
RateLimit *ConfigRateLimit `json:"rateLimit,omitempty"`
|
||||||
@@ -606,12 +651,15 @@ type ConfigFunctionsUpdateInput struct {
|
|||||||
Resources *ConfigFunctionsResourcesUpdateInput `json:"resources,omitempty"`
|
Resources *ConfigFunctionsResourcesUpdateInput `json:"resources,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Global configuration that applies to all services
|
||||||
type ConfigGlobal struct {
|
type ConfigGlobal struct {
|
||||||
|
// User-defined environment variables that are spread over all services
|
||||||
Environment []*ConfigGlobalEnvironmentVariable `json:"environment,omitempty"`
|
Environment []*ConfigGlobalEnvironmentVariable `json:"environment,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigGlobalEnvironmentVariable struct {
|
type ConfigGlobalEnvironmentVariable struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
// Value of the environment variable
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -768,23 +816,34 @@ type ConfigGraphqlUpdateInput struct {
|
|||||||
Security *ConfigGraphqlSecurityUpdateInput `json:"security,omitempty"`
|
Security *ConfigGraphqlSecurityUpdateInput `json:"security,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configuration for hasura service
|
||||||
type ConfigHasura struct {
|
type ConfigHasura struct {
|
||||||
AdminSecret string `json:"adminSecret"`
|
// Admin secret
|
||||||
AuthHook *ConfigHasuraAuthHook `json:"authHook,omitempty"`
|
AdminSecret string `json:"adminSecret"`
|
||||||
Events *ConfigHasuraEvents `json:"events,omitempty"`
|
AuthHook *ConfigHasuraAuthHook `json:"authHook,omitempty"`
|
||||||
JwtSecrets []*ConfigJWTSecret `json:"jwtSecrets,omitempty"`
|
Events *ConfigHasuraEvents `json:"events,omitempty"`
|
||||||
Logs *ConfigHasuraLogs `json:"logs,omitempty"`
|
// JWT Secrets configuration
|
||||||
RateLimit *ConfigRateLimit `json:"rateLimit,omitempty"`
|
JwtSecrets []*ConfigJWTSecret `json:"jwtSecrets,omitempty"`
|
||||||
Resources *ConfigResources `json:"resources,omitempty"`
|
Logs *ConfigHasuraLogs `json:"logs,omitempty"`
|
||||||
Settings *ConfigHasuraSettings `json:"settings,omitempty"`
|
RateLimit *ConfigRateLimit `json:"rateLimit,omitempty"`
|
||||||
Version *string `json:"version,omitempty"`
|
// Resources for the service
|
||||||
WebhookSecret string `json:"webhookSecret"`
|
Resources *ConfigResources `json:"resources,omitempty"`
|
||||||
|
// Configuration for hasura services
|
||||||
|
// Reference: https://hasura.io/docs/latest/deployment/graphql-engine-flags/reference/
|
||||||
|
Settings *ConfigHasuraSettings `json:"settings,omitempty"`
|
||||||
|
// Version of hasura, you can see available versions in the URL below:
|
||||||
|
// https://hub.docker.com/r/hasura/graphql-engine/tags
|
||||||
|
Version *string `json:"version,omitempty"`
|
||||||
|
// Webhook secret
|
||||||
|
WebhookSecret string `json:"webhookSecret"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigHasuraAuthHook struct {
|
type ConfigHasuraAuthHook struct {
|
||||||
Mode *string `json:"mode,omitempty"`
|
Mode *string `json:"mode,omitempty"`
|
||||||
SendRequestBody *bool `json:"sendRequestBody,omitempty"`
|
// HASURA_GRAPHQL_AUTH_HOOK_SEND_REQUEST_BODY
|
||||||
URL string `json:"url"`
|
SendRequestBody *bool `json:"sendRequestBody,omitempty"`
|
||||||
|
// HASURA_GRAPHQL_AUTH_HOOK
|
||||||
|
URL string `json:"url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigHasuraAuthHookUpdateInput struct {
|
type ConfigHasuraAuthHookUpdateInput struct {
|
||||||
@@ -794,6 +853,7 @@ type ConfigHasuraAuthHookUpdateInput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ConfigHasuraEvents struct {
|
type ConfigHasuraEvents struct {
|
||||||
|
// HASURA_GRAPHQL_EVENTS_HTTP_POOL_SIZE
|
||||||
HTTPPoolSize *uint32 `json:"httpPoolSize,omitempty"`
|
HTTPPoolSize *uint32 `json:"httpPoolSize,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -809,16 +869,27 @@ type ConfigHasuraLogsUpdateInput struct {
|
|||||||
Level *string `json:"level,omitempty"`
|
Level *string `json:"level,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configuration for hasura services
|
||||||
|
// Reference: https://hasura.io/docs/latest/deployment/graphql-engine-flags/reference/
|
||||||
type ConfigHasuraSettings struct {
|
type ConfigHasuraSettings struct {
|
||||||
CorsDomain []string `json:"corsDomain,omitempty"`
|
// HASURA_GRAPHQL_CORS_DOMAIN
|
||||||
DevMode *bool `json:"devMode,omitempty"`
|
CorsDomain []string `json:"corsDomain,omitempty"`
|
||||||
EnableAllowList *bool `json:"enableAllowList,omitempty"`
|
// HASURA_GRAPHQL_DEV_MODE
|
||||||
EnableConsole *bool `json:"enableConsole,omitempty"`
|
DevMode *bool `json:"devMode,omitempty"`
|
||||||
EnableRemoteSchemaPermissions *bool `json:"enableRemoteSchemaPermissions,omitempty"`
|
// HASURA_GRAPHQL_ENABLE_ALLOWLIST
|
||||||
EnabledAPIs []string `json:"enabledAPIs,omitempty"`
|
EnableAllowList *bool `json:"enableAllowList,omitempty"`
|
||||||
InferFunctionPermissions *bool `json:"inferFunctionPermissions,omitempty"`
|
// HASURA_GRAPHQL_ENABLE_CONSOLE
|
||||||
LiveQueriesMultiplexedRefetchInterval *uint32 `json:"liveQueriesMultiplexedRefetchInterval,omitempty"`
|
EnableConsole *bool `json:"enableConsole,omitempty"`
|
||||||
StringifyNumericTypes *bool `json:"stringifyNumericTypes,omitempty"`
|
// HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS
|
||||||
|
EnableRemoteSchemaPermissions *bool `json:"enableRemoteSchemaPermissions,omitempty"`
|
||||||
|
// HASURA_GRAPHQL_ENABLED_APIS
|
||||||
|
EnabledAPIs []string `json:"enabledAPIs,omitempty"`
|
||||||
|
// HASURA_GRAPHQL_INFER_FUNCTION_PERMISSIONS
|
||||||
|
InferFunctionPermissions *bool `json:"inferFunctionPermissions,omitempty"`
|
||||||
|
// HASURA_GRAPHQL_LIVE_QUERIES_MULTIPLEXED_REFETCH_INTERVAL
|
||||||
|
LiveQueriesMultiplexedRefetchInterval *uint32 `json:"liveQueriesMultiplexedRefetchInterval,omitempty"`
|
||||||
|
// HASURA_GRAPHQL_STRINGIFY_NUMERIC_TYPES
|
||||||
|
StringifyNumericTypes *bool `json:"stringifyNumericTypes,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigHasuraSettingsUpdateInput struct {
|
type ConfigHasuraSettingsUpdateInput struct {
|
||||||
@@ -891,6 +962,7 @@ type ConfigIngressUpdateInput struct {
|
|||||||
TLS *ConfigIngressTLSUpdateInput `json:"tls,omitempty"`
|
TLS *ConfigIngressTLSUpdateInput `json:"tls,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See https://hasura.io/docs/latest/auth/authentication/jwt/
|
||||||
type ConfigJWTSecret struct {
|
type ConfigJWTSecret struct {
|
||||||
AllowedSkew *uint32 `json:"allowed_skew,omitempty"`
|
AllowedSkew *uint32 `json:"allowed_skew,omitempty"`
|
||||||
Audience *string `json:"audience,omitempty"`
|
Audience *string `json:"audience,omitempty"`
|
||||||
@@ -939,11 +1011,15 @@ type ConfigObservabilityUpdateInput struct {
|
|||||||
Grafana *ConfigGrafanaUpdateInput `json:"grafana,omitempty"`
|
Grafana *ConfigGrafanaUpdateInput `json:"grafana,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configuration for postgres service
|
||||||
type ConfigPostgres struct {
|
type ConfigPostgres struct {
|
||||||
Pitr *ConfigPostgresPitr `json:"pitr,omitempty"`
|
Pitr *ConfigPostgresPitr `json:"pitr,omitempty"`
|
||||||
|
// Resources for the service
|
||||||
Resources *ConfigPostgresResources `json:"resources"`
|
Resources *ConfigPostgresResources `json:"resources"`
|
||||||
Settings *ConfigPostgresSettings `json:"settings,omitempty"`
|
Settings *ConfigPostgresSettings `json:"settings,omitempty"`
|
||||||
Version *string `json:"version,omitempty"`
|
// Version of postgres, you can see available versions in the URL below:
|
||||||
|
// https://hub.docker.com/r/nhost/postgres/tags
|
||||||
|
Version *string `json:"version,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigPostgresPitr struct {
|
type ConfigPostgresPitr struct {
|
||||||
@@ -954,6 +1030,7 @@ type ConfigPostgresPitrUpdateInput struct {
|
|||||||
Retention *uint32 `json:"retention,omitempty"`
|
Retention *uint32 `json:"retention,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resources for the service
|
||||||
type ConfigPostgresResources struct {
|
type ConfigPostgresResources struct {
|
||||||
Compute *ConfigResourcesCompute `json:"compute,omitempty"`
|
Compute *ConfigResourcesCompute `json:"compute,omitempty"`
|
||||||
EnablePublicAccess *bool `json:"enablePublicAccess,omitempty"`
|
EnablePublicAccess *bool `json:"enablePublicAccess,omitempty"`
|
||||||
@@ -1060,15 +1137,19 @@ type ConfigRateLimitUpdateInput struct {
|
|||||||
Limit *uint32 `json:"limit,omitempty"`
|
Limit *uint32 `json:"limit,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resource configuration for a service
|
||||||
type ConfigResources struct {
|
type ConfigResources struct {
|
||||||
Autoscaler *ConfigAutoscaler `json:"autoscaler,omitempty"`
|
Autoscaler *ConfigAutoscaler `json:"autoscaler,omitempty"`
|
||||||
Compute *ConfigResourcesCompute `json:"compute,omitempty"`
|
Compute *ConfigResourcesCompute `json:"compute,omitempty"`
|
||||||
Networking *ConfigNetworking `json:"networking,omitempty"`
|
Networking *ConfigNetworking `json:"networking,omitempty"`
|
||||||
Replicas *uint32 `json:"replicas,omitempty"`
|
// Number of replicas for a service
|
||||||
|
Replicas *uint32 `json:"replicas,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigResourcesCompute struct {
|
type ConfigResourcesCompute struct {
|
||||||
CPU uint32 `json:"cpu"`
|
// milicpus, 1000 milicpus = 1 cpu
|
||||||
|
CPU uint32 `json:"cpu"`
|
||||||
|
// MiB: 128MiB to 30GiB
|
||||||
Memory uint32 `json:"memory"`
|
Memory uint32 `json:"memory"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1120,7 +1201,8 @@ type ConfigRunServiceConfigWithID struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ConfigRunServiceImage struct {
|
type ConfigRunServiceImage struct {
|
||||||
Image string `json:"image"`
|
Image string `json:"image"`
|
||||||
|
// content of "auths", i.e., { "auths": $THIS }
|
||||||
PullCredentials *string `json:"pullCredentials,omitempty"`
|
PullCredentials *string `json:"pullCredentials,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1158,11 +1240,13 @@ type ConfigRunServicePortUpdateInput struct {
|
|||||||
Type *string `json:"type,omitempty"`
|
Type *string `json:"type,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resource configuration for a service
|
||||||
type ConfigRunServiceResources struct {
|
type ConfigRunServiceResources struct {
|
||||||
Autoscaler *ConfigAutoscaler `json:"autoscaler,omitempty"`
|
Autoscaler *ConfigAutoscaler `json:"autoscaler,omitempty"`
|
||||||
Compute *ConfigComputeResources `json:"compute"`
|
Compute *ConfigComputeResources `json:"compute"`
|
||||||
Replicas uint32 `json:"replicas"`
|
// Number of replicas for a service
|
||||||
Storage []*ConfigRunServiceResourcesStorage `json:"storage,omitempty"`
|
Replicas uint32 `json:"replicas"`
|
||||||
|
Storage []*ConfigRunServiceResourcesStorage `json:"storage,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigRunServiceResourcesInsertInput struct {
|
type ConfigRunServiceResourcesInsertInput struct {
|
||||||
@@ -1173,9 +1257,11 @@ type ConfigRunServiceResourcesInsertInput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ConfigRunServiceResourcesStorage struct {
|
type ConfigRunServiceResourcesStorage struct {
|
||||||
|
// GiB
|
||||||
Capacity uint32 `json:"capacity"`
|
Capacity uint32 `json:"capacity"`
|
||||||
Name string `json:"name"`
|
// name of the volume, changing it will cause data loss
|
||||||
Path string `json:"path"`
|
Name string `json:"name"`
|
||||||
|
Path string `json:"path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigRunServiceResourcesStorageInsertInput struct {
|
type ConfigRunServiceResourcesStorageInsertInput struct {
|
||||||
@@ -1259,11 +1345,20 @@ type ConfigStandardOauthProviderWithScopeUpdateInput struct {
|
|||||||
Scope []string `json:"scope,omitempty"`
|
Scope []string `json:"scope,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configuration for storage service
|
||||||
type ConfigStorage struct {
|
type ConfigStorage struct {
|
||||||
Antivirus *ConfigStorageAntivirus `json:"antivirus,omitempty"`
|
Antivirus *ConfigStorageAntivirus `json:"antivirus,omitempty"`
|
||||||
RateLimit *ConfigRateLimit `json:"rateLimit,omitempty"`
|
RateLimit *ConfigRateLimit `json:"rateLimit,omitempty"`
|
||||||
Resources *ConfigResources `json:"resources,omitempty"`
|
// Networking (custom domains at the moment) are not allowed as we need to do further
|
||||||
Version *string `json:"version,omitempty"`
|
// configurations in the CDN. We will enable it again in the future.
|
||||||
|
Resources *ConfigResources `json:"resources,omitempty"`
|
||||||
|
// Version of storage service, you can see available versions in the URL below:
|
||||||
|
// https://hub.docker.com/r/nhost/hasura-storage/tags
|
||||||
|
//
|
||||||
|
// Releases:
|
||||||
|
//
|
||||||
|
// https://github.com/nhost/hasura-storage/releases
|
||||||
|
Version *string `json:"version,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigStorageAntivirus struct {
|
type ConfigStorageAntivirus struct {
|
||||||
@@ -1301,6 +1396,8 @@ type ConfigSystemConfigAuthEmailTemplates struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ConfigSystemConfigGraphql struct {
|
type ConfigSystemConfigGraphql struct {
|
||||||
|
// manually enable graphi on a per-service basis
|
||||||
|
// by default it follows the plan
|
||||||
FeatureAdvancedGraphql *bool `json:"featureAdvancedGraphql,omitempty"`
|
FeatureAdvancedGraphql *bool `json:"featureAdvancedGraphql,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1718,7 +1815,8 @@ type Apps struct {
|
|||||||
AppStates []*AppStateHistory `json:"appStates"`
|
AppStates []*AppStateHistory `json:"appStates"`
|
||||||
AutomaticDeploys bool `json:"automaticDeploys"`
|
AutomaticDeploys bool `json:"automaticDeploys"`
|
||||||
// An array relationship
|
// An array relationship
|
||||||
Backups []*Backups `json:"backups"`
|
Backups []*Backups `json:"backups"`
|
||||||
|
// main entrypoint to the configuration
|
||||||
Config *ConfigConfig `json:"config,omitempty"`
|
Config *ConfigConfig `json:"config,omitempty"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
// An object relationship
|
// An object relationship
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ NEXT_PUBLIC_ANALYTICS_WRITE_KEY=<analytics_write_key>
|
|||||||
NEXT_PUBLIC_SEGMENT_CDN_URL=<segment_cdn_url>
|
NEXT_PUBLIC_SEGMENT_CDN_URL=<segment_cdn_url>
|
||||||
NEXT_PUBLIC_NHOST_BRAGI_WEBSOCKET=<nhost_bragi_websocket>
|
NEXT_PUBLIC_NHOST_BRAGI_WEBSOCKET=<nhost_bragi_websocket>
|
||||||
|
|
||||||
NEXT_PUBLIC_ZENDESK_URL=
|
NEXT_ZENDESK_URL=
|
||||||
NEXT_PUBLIC_ZENDESK_API_KEY=
|
NEXT_ZENDESK_API_KEY=
|
||||||
NEXT_PUBLIC_ZENDESK_USER_EMAIL=
|
NEXT_ZENDESK_USER_EMAIL=
|
||||||
|
|
||||||
|
|
||||||
CODEGEN_GRAPHQL_URL=https://local.graphql.local.nhost.run/v1
|
CODEGEN_GRAPHQL_URL=https://local.graphql.local.nhost.run/v1
|
||||||
CODEGEN_HASURA_ADMIN_SECRET=nhost-admin-secret
|
CODEGEN_HASURA_ADMIN_SECRET=nhost-admin-secret
|
||||||
NEXT_PUBLIC_TURNSTILE_SITE_KEY=FIXME
|
NEXT_PUBLIC_TURNSTILE_SITE_KEY=FIXME
|
||||||
|
|
||||||
NEXT_PUBLIC_SOC2_REPORT_FILE_ID=
|
NEXT_PUBLIC_SOC2_REPORT_FILE_ID=
|
||||||
|
|||||||
@@ -2,6 +2,23 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [@nhost/dashboard@2.39.0] - 2025-10-22
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- *(dashboard)* Move zendesk request to API route (#3628)
|
||||||
|
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- *(dashboard)* Fix flaky e2e tests (#3536)
|
||||||
|
- *(dashboard)* Run audit and lint in dashboard (#3578)
|
||||||
|
|
||||||
|
|
||||||
|
### ⚙️ Miscellaneous Tasks
|
||||||
|
|
||||||
|
- *(dashboard)* Cleanup e2e remote schemas test before run (#3581)
|
||||||
|
|
||||||
## [@nhost/dashboard@2.38.4] - 2025-10-09
|
## [@nhost/dashboard@2.38.4] - 2025-10-09
|
||||||
|
|
||||||
### 🐛 Bug Fixes
|
### 🐛 Bug Fixes
|
||||||
|
|||||||
@@ -196,7 +196,7 @@
|
|||||||
"tailwindcss": "^3.4.12",
|
"tailwindcss": "^3.4.12",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"tsconfig-paths-webpack-plugin": "^4.1.0",
|
"tsconfig-paths-webpack-plugin": "^4.1.0",
|
||||||
"vite": "^5.4.20",
|
"vite": "^5.4.21",
|
||||||
"vite-tsconfig-paths": "^4.3.2",
|
"vite-tsconfig-paths": "^4.3.2",
|
||||||
"vitest": "^3.2.4"
|
"vitest": "^3.2.4"
|
||||||
},
|
},
|
||||||
|
|||||||
34
dashboard/pnpm-lock.yaml
generated
34
dashboard/pnpm-lock.yaml
generated
@@ -415,7 +415,7 @@ importers:
|
|||||||
version: 6.21.0(eslint@8.57.0)(typescript@5.8.3)
|
version: 6.21.0(eslint@8.57.0)(typescript@5.8.3)
|
||||||
'@vitejs/plugin-react':
|
'@vitejs/plugin-react':
|
||||||
specifier: ^4.7.0
|
specifier: ^4.7.0
|
||||||
version: 4.7.0(vite@5.4.20(@types/node@20.14.8)(terser@5.44.0))
|
version: 4.7.0(vite@5.4.21(@types/node@20.14.8)(terser@5.44.0))
|
||||||
'@vitest/coverage-v8':
|
'@vitest/coverage-v8':
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.4
|
||||||
version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@20.14.8)(jsdom@22.1.0)(msw@2.11.4(@types/node@20.14.8)(typescript@5.8.3))(terser@5.44.0))
|
version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@20.14.8)(jsdom@22.1.0)(msw@2.11.4(@types/node@20.14.8)(typescript@5.8.3))(terser@5.44.0))
|
||||||
@@ -525,11 +525,11 @@ importers:
|
|||||||
specifier: ^4.1.0
|
specifier: ^4.1.0
|
||||||
version: 4.2.0
|
version: 4.2.0
|
||||||
vite:
|
vite:
|
||||||
specifier: ^5.4.20
|
specifier: ^5.4.21
|
||||||
version: 5.4.20(@types/node@20.14.8)(terser@5.44.0)
|
version: 5.4.21(@types/node@20.14.8)(terser@5.44.0)
|
||||||
vite-tsconfig-paths:
|
vite-tsconfig-paths:
|
||||||
specifier: ^4.3.2
|
specifier: ^4.3.2
|
||||||
version: 4.3.2(typescript@5.8.3)(vite@5.4.20(@types/node@20.14.8)(terser@5.44.0))
|
version: 4.3.2(typescript@5.8.3)(vite@5.4.21(@types/node@20.14.8)(terser@5.44.0))
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.4
|
||||||
version: 3.2.4(@types/debug@4.1.12)(@types/node@20.14.8)(jsdom@22.1.0)(msw@2.11.4(@types/node@20.14.8)(typescript@5.8.3))(terser@5.44.0)
|
version: 3.2.4(@types/debug@4.1.12)(@types/node@20.14.8)(jsdom@22.1.0)(msw@2.11.4(@types/node@20.14.8)(typescript@5.8.3))(terser@5.44.0)
|
||||||
@@ -8576,13 +8576,13 @@ packages:
|
|||||||
vite-tsconfig-paths@4.3.2:
|
vite-tsconfig-paths@4.3.2:
|
||||||
resolution: {integrity: sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA==}
|
resolution: {integrity: sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vite: '*'
|
vite: '>=4.5.14'
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
vite:
|
vite:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
vite@5.4.20:
|
vite@5.4.21:
|
||||||
resolution: {integrity: sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==}
|
resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==}
|
||||||
engines: {node: ^18.0.0 || >=20.0.0}
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -13299,7 +13299,7 @@ snapshots:
|
|||||||
|
|
||||||
'@ungap/structured-clone@1.2.0': {}
|
'@ungap/structured-clone@1.2.0': {}
|
||||||
|
|
||||||
'@vitejs/plugin-react@4.7.0(vite@5.4.20(@types/node@20.14.8)(terser@5.44.0))':
|
'@vitejs/plugin-react@4.7.0(vite@5.4.21(@types/node@20.14.8)(terser@5.44.0))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.28.4
|
'@babel/core': 7.28.4
|
||||||
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4)
|
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4)
|
||||||
@@ -13307,7 +13307,7 @@ snapshots:
|
|||||||
'@rolldown/pluginutils': 1.0.0-beta.27
|
'@rolldown/pluginutils': 1.0.0-beta.27
|
||||||
'@types/babel__core': 7.20.5
|
'@types/babel__core': 7.20.5
|
||||||
react-refresh: 0.17.0
|
react-refresh: 0.17.0
|
||||||
vite: 5.4.20(@types/node@20.14.8)(terser@5.44.0)
|
vite: 5.4.21(@types/node@20.14.8)(terser@5.44.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -13338,14 +13338,14 @@ snapshots:
|
|||||||
chai: 5.3.3
|
chai: 5.3.3
|
||||||
tinyrainbow: 2.0.0
|
tinyrainbow: 2.0.0
|
||||||
|
|
||||||
'@vitest/mocker@3.2.4(msw@2.11.4(@types/node@20.14.8)(typescript@5.8.3))(vite@5.4.20(@types/node@20.14.8)(terser@5.44.0))':
|
'@vitest/mocker@3.2.4(msw@2.11.4(@types/node@20.14.8)(typescript@5.8.3))(vite@5.4.21(@types/node@20.14.8)(terser@5.44.0))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/spy': 3.2.4
|
'@vitest/spy': 3.2.4
|
||||||
estree-walker: 3.0.3
|
estree-walker: 3.0.3
|
||||||
magic-string: 0.30.19
|
magic-string: 0.30.19
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
msw: 2.11.4(@types/node@20.14.8)(typescript@5.8.3)
|
msw: 2.11.4(@types/node@20.14.8)(typescript@5.8.3)
|
||||||
vite: 5.4.20(@types/node@20.14.8)(terser@5.44.0)
|
vite: 5.4.21(@types/node@20.14.8)(terser@5.44.0)
|
||||||
|
|
||||||
'@vitest/pretty-format@3.2.4':
|
'@vitest/pretty-format@3.2.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -18484,7 +18484,7 @@ snapshots:
|
|||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
es-module-lexer: 1.7.0
|
es-module-lexer: 1.7.0
|
||||||
pathe: 2.0.3
|
pathe: 2.0.3
|
||||||
vite: 5.4.20(@types/node@20.14.8)(terser@5.44.0)
|
vite: 5.4.21(@types/node@20.14.8)(terser@5.44.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/node'
|
- '@types/node'
|
||||||
- less
|
- less
|
||||||
@@ -18496,18 +18496,18 @@ snapshots:
|
|||||||
- supports-color
|
- supports-color
|
||||||
- terser
|
- terser
|
||||||
|
|
||||||
vite-tsconfig-paths@4.3.2(typescript@5.8.3)(vite@5.4.20(@types/node@20.14.8)(terser@5.44.0)):
|
vite-tsconfig-paths@4.3.2(typescript@5.8.3)(vite@5.4.21(@types/node@20.14.8)(terser@5.44.0)):
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.1
|
debug: 4.4.1
|
||||||
globrex: 0.1.2
|
globrex: 0.1.2
|
||||||
tsconfck: 3.1.6(typescript@5.8.3)
|
tsconfck: 3.1.6(typescript@5.8.3)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 5.4.20(@types/node@20.14.8)(terser@5.44.0)
|
vite: 5.4.21(@types/node@20.14.8)(terser@5.44.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
- typescript
|
- typescript
|
||||||
|
|
||||||
vite@5.4.20(@types/node@20.14.8)(terser@5.44.0):
|
vite@5.4.21(@types/node@20.14.8)(terser@5.44.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.25.10
|
esbuild: 0.25.10
|
||||||
postcss: 8.5.3
|
postcss: 8.5.3
|
||||||
@@ -18521,7 +18521,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@types/chai': 5.2.2
|
'@types/chai': 5.2.2
|
||||||
'@vitest/expect': 3.2.4
|
'@vitest/expect': 3.2.4
|
||||||
'@vitest/mocker': 3.2.4(msw@2.11.4(@types/node@20.14.8)(typescript@5.8.3))(vite@5.4.20(@types/node@20.14.8)(terser@5.44.0))
|
'@vitest/mocker': 3.2.4(msw@2.11.4(@types/node@20.14.8)(typescript@5.8.3))(vite@5.4.21(@types/node@20.14.8)(terser@5.44.0))
|
||||||
'@vitest/pretty-format': 3.2.4
|
'@vitest/pretty-format': 3.2.4
|
||||||
'@vitest/runner': 3.2.4
|
'@vitest/runner': 3.2.4
|
||||||
'@vitest/snapshot': 3.2.4
|
'@vitest/snapshot': 3.2.4
|
||||||
@@ -18539,7 +18539,7 @@ snapshots:
|
|||||||
tinyglobby: 0.2.15
|
tinyglobby: 0.2.15
|
||||||
tinypool: 1.1.1
|
tinypool: 1.1.1
|
||||||
tinyrainbow: 2.0.0
|
tinyrainbow: 2.0.0
|
||||||
vite: 5.4.20(@types/node@20.14.8)(terser@5.44.0)
|
vite: 5.4.21(@types/node@20.14.8)(terser@5.44.0)
|
||||||
vite-node: 3.2.4(@types/node@20.14.8)(terser@5.44.0)
|
vite-node: 3.2.4(@types/node@20.14.8)(terser@5.44.0)
|
||||||
why-is-node-running: 2.3.0
|
why-is-node-running: 2.3.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
|
|||||||
165
dashboard/src/pages/api/support/create-ticket.ts
Normal file
165
dashboard/src/pages/api/support/create-ticket.ts
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
import { nhostRoutesClient } from '@/utils/nhost';
|
||||||
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
|
||||||
|
export type CreateTicketRequest = {
|
||||||
|
project: string;
|
||||||
|
services: Array<{ label: string; value: string }>;
|
||||||
|
priority: string;
|
||||||
|
subject: string;
|
||||||
|
description: string;
|
||||||
|
userName: string;
|
||||||
|
userEmail: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CreateTicketResponse = {
|
||||||
|
success: boolean;
|
||||||
|
error?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type GetProjectResponse = {
|
||||||
|
apps: Array<{
|
||||||
|
id: string;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function handler(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse<CreateTicketResponse>,
|
||||||
|
) {
|
||||||
|
if (req.method !== 'POST') {
|
||||||
|
return res
|
||||||
|
.status(405)
|
||||||
|
.json({ success: false, error: 'Method not allowed' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const {
|
||||||
|
project,
|
||||||
|
services,
|
||||||
|
priority,
|
||||||
|
subject,
|
||||||
|
description,
|
||||||
|
userName,
|
||||||
|
userEmail,
|
||||||
|
} = req.body as CreateTicketRequest;
|
||||||
|
|
||||||
|
// Validate required environment variables
|
||||||
|
if (
|
||||||
|
!process.env.NEXT_ZENDESK_USER_EMAIL ||
|
||||||
|
!process.env.NEXT_ZENDESK_API_KEY ||
|
||||||
|
!process.env.NEXT_ZENDESK_URL
|
||||||
|
) {
|
||||||
|
return res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
error: 'Zendesk configuration is missing',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate required fields
|
||||||
|
if (
|
||||||
|
!project ||
|
||||||
|
!services ||
|
||||||
|
!priority ||
|
||||||
|
!subject ||
|
||||||
|
!description ||
|
||||||
|
!userName ||
|
||||||
|
!userEmail
|
||||||
|
) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
error: 'Missing required fields',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const token = req.headers.authorization?.split(' ')[1];
|
||||||
|
|
||||||
|
try {
|
||||||
|
// we use this to verify the owner of the JWT token has access to the project
|
||||||
|
const resp = await nhostRoutesClient.graphql.request<GetProjectResponse>(
|
||||||
|
{
|
||||||
|
query: `query GetProject($subdomain: String!){
|
||||||
|
apps(where: {subdomain: {_eq: $subdomain}}) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
variables: {
|
||||||
|
subdomain: project,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (resp.body.data?.apps.length !== 1) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
error: 'Invalid project subdomain',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
error: 'Invalid project subdomain',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const auth = btoa(
|
||||||
|
`${process.env.NEXT_ZENDESK_USER_EMAIL}/token:${process.env.NEXT_ZENDESK_API_KEY}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
`${process.env.NEXT_ZENDESK_URL}/api/v2/requests.json`,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Authorization: `Basic ${auth}`,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
request: {
|
||||||
|
subject,
|
||||||
|
comment: {
|
||||||
|
body: description,
|
||||||
|
},
|
||||||
|
priority,
|
||||||
|
requester: {
|
||||||
|
name: userName,
|
||||||
|
email: userEmail,
|
||||||
|
},
|
||||||
|
custom_fields: [
|
||||||
|
// these custom field IDs come from zendesk
|
||||||
|
{
|
||||||
|
id: 19502784542098,
|
||||||
|
value: project,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 19922709880978,
|
||||||
|
value: services.map((service) => service.value?.toLowerCase()),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorText = await response.text();
|
||||||
|
console.error('Zendesk API error:', errorText);
|
||||||
|
return res.status(response.status).json({
|
||||||
|
success: false,
|
||||||
|
error: `Failed to create ticket: ${response.statusText}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.status(200).json({ success: true });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error creating ticket:', error);
|
||||||
|
return res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
error: 'An unexpected error occurred',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import { Input, inputClasses } from '@/components/ui/v2/Input';
|
|||||||
import { Option } from '@/components/ui/v2/Option';
|
import { Option } from '@/components/ui/v2/Option';
|
||||||
import { Text } from '@/components/ui/v2/Text';
|
import { Text } from '@/components/ui/v2/Text';
|
||||||
import { execPromiseWithErrorToast } from '@/features/orgs/utils/execPromiseWithErrorToast';
|
import { execPromiseWithErrorToast } from '@/features/orgs/utils/execPromiseWithErrorToast';
|
||||||
|
import { useAccessToken } from '@/hooks/useAccessToken';
|
||||||
import { useUserData } from '@/hooks/useUserData';
|
import { useUserData } from '@/hooks/useUserData';
|
||||||
import {
|
import {
|
||||||
useGetOrganizationsQuery,
|
useGetOrganizationsQuery,
|
||||||
@@ -36,7 +37,6 @@ const validationSchema = Yup.object({
|
|||||||
priority: Yup.string().label('Priority').required(),
|
priority: Yup.string().label('Priority').required(),
|
||||||
subject: Yup.string().label('Subject').required(),
|
subject: Yup.string().label('Subject').required(),
|
||||||
description: Yup.string().label('Description').required(),
|
description: Yup.string().label('Description').required(),
|
||||||
ccs: Yup.string().label('CCs').optional(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type CreateTicketFormValues = Yup.InferType<typeof validationSchema>;
|
export type CreateTicketFormValues = Yup.InferType<typeof validationSchema>;
|
||||||
@@ -58,7 +58,6 @@ function TicketPage() {
|
|||||||
priority: '',
|
priority: '',
|
||||||
subject: '',
|
subject: '',
|
||||||
description: '',
|
description: '',
|
||||||
ccs: '',
|
|
||||||
},
|
},
|
||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
});
|
});
|
||||||
@@ -71,6 +70,7 @@ function TicketPage() {
|
|||||||
|
|
||||||
const selectedOrganization = watch('organization');
|
const selectedOrganization = watch('organization');
|
||||||
const user = useUserData();
|
const user = useUserData();
|
||||||
|
const token = useAccessToken();
|
||||||
|
|
||||||
const { data: organizationsData } = useGetOrganizationsQuery({
|
const { data: organizationsData } = useGetOrganizationsQuery({
|
||||||
variables: {
|
variables: {
|
||||||
@@ -91,56 +91,32 @@ function TicketPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = async (formValues: CreateTicketFormValues) => {
|
const handleSubmit = async (formValues: CreateTicketFormValues) => {
|
||||||
const { project, services, priority, subject, description, ccs } =
|
const { project, services, priority, subject, description } = formValues;
|
||||||
formValues;
|
|
||||||
|
|
||||||
const auth = btoa(
|
|
||||||
`${process.env.NEXT_PUBLIC_ZENDESK_USER_EMAIL}/token:${process.env.NEXT_PUBLIC_ZENDESK_API_KEY}`,
|
|
||||||
);
|
|
||||||
const emails = ccs
|
|
||||||
?.replace(/ /g, '')
|
|
||||||
.split(',')
|
|
||||||
.map((email) => ({ user_email: email }));
|
|
||||||
|
|
||||||
await execPromiseWithErrorToast(
|
await execPromiseWithErrorToast(
|
||||||
async () => {
|
async () => {
|
||||||
await fetch(
|
const response = await fetch('/api/support/create-ticket', {
|
||||||
`${process.env.NEXT_PUBLIC_ZENDESK_URL}/api/v2/requests.json`,
|
method: 'POST',
|
||||||
{
|
headers: {
|
||||||
method: 'POST',
|
'Content-Type': 'application/json',
|
||||||
headers: {
|
Authorization: `Bearer ${token}`,
|
||||||
'Content-Type': 'application/json',
|
|
||||||
Authorization: `Basic ${auth}`,
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
request: {
|
|
||||||
subject,
|
|
||||||
comment: {
|
|
||||||
body: description,
|
|
||||||
},
|
|
||||||
priority,
|
|
||||||
requester: {
|
|
||||||
name: user?.displayName,
|
|
||||||
email: user?.email,
|
|
||||||
},
|
|
||||||
email_ccs: emails,
|
|
||||||
custom_fields: [
|
|
||||||
// these custom field IDs come from zendesk
|
|
||||||
{
|
|
||||||
id: 19502784542098,
|
|
||||||
value: project,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 19922709880978,
|
|
||||||
value: services.map((service) =>
|
|
||||||
service.value?.toLowerCase(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
);
|
body: JSON.stringify({
|
||||||
|
project,
|
||||||
|
services,
|
||||||
|
priority,
|
||||||
|
subject,
|
||||||
|
description,
|
||||||
|
userName: user?.displayName,
|
||||||
|
userEmail: user?.email,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const error = await response.json();
|
||||||
|
throw new Error(error.error || 'Failed to create ticket');
|
||||||
|
}
|
||||||
|
|
||||||
form.reset();
|
form.reset();
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -330,21 +306,6 @@ function TicketPage() {
|
|||||||
helperText={errors.description?.message}
|
helperText={errors.description?.message}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Divider />
|
|
||||||
|
|
||||||
<Text className="mt-4 font-bold">Notifications</Text>
|
|
||||||
|
|
||||||
<StyledInput
|
|
||||||
{...register('ccs')}
|
|
||||||
id="ccs"
|
|
||||||
label="CCs"
|
|
||||||
placeholder="Comma separated list of emails you want to share this ticket with."
|
|
||||||
fullWidth
|
|
||||||
inputProps={{ min: 2, max: 128 }}
|
|
||||||
error={!!errors.ccs}
|
|
||||||
helperText={errors.ccs?.message}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Box className="ml-auto flex w-80 flex-col gap-4">
|
<Box className="ml-auto flex w-80 flex-col gap-4">
|
||||||
<Text color="secondary" className="text-right text-sm">
|
<Text color="secondary" className="text-right text-sm">
|
||||||
We will contact you at <strong>{user?.email}</strong>
|
We will contact you at <strong>{user?.email}</strong>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
getGraphqlServiceUrl,
|
getGraphqlServiceUrl,
|
||||||
getStorageServiceUrl,
|
getStorageServiceUrl,
|
||||||
} from '@/utils/env';
|
} from '@/utils/env';
|
||||||
import { createClient } from '@nhost/nhost-js';
|
import { createClient, createNhostClient } from '@nhost/nhost-js';
|
||||||
import { type Session, type SessionStorageBackend } from '@nhost/nhost-js/session';
|
import { type Session, type SessionStorageBackend } from '@nhost/nhost-js/session';
|
||||||
|
|
||||||
const nhost = createClient({
|
const nhost = createClient({
|
||||||
@@ -14,6 +14,13 @@ const nhost = createClient({
|
|||||||
storageUrl: getStorageServiceUrl(),
|
storageUrl: getStorageServiceUrl(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const nhostRoutesClient = createNhostClient({
|
||||||
|
authUrl: getAuthServiceUrl(),
|
||||||
|
graphqlUrl: getGraphqlServiceUrl(),
|
||||||
|
functionsUrl: getFunctionsServiceUrl(),
|
||||||
|
storageUrl: getStorageServiceUrl(),
|
||||||
|
});
|
||||||
|
|
||||||
export class DummySessionStorage implements SessionStorageBackend {
|
export class DummySessionStorage implements SessionStorageBackend {
|
||||||
private session: Session | null = null;
|
private session: Session | null = null;
|
||||||
|
|
||||||
@@ -41,4 +48,5 @@ export class DummySessionStorage implements SessionStorageBackend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export { nhostRoutesClient };
|
||||||
export default nhost;
|
export default nhost;
|
||||||
|
|||||||
@@ -120,21 +120,26 @@ sender = 'myapp@mydomain.com'
|
|||||||
It is very important that the `host` is set exactly to `postmark`.
|
It is very important that the `host` is set exactly to `postmark`.
|
||||||
</Warning>
|
</Warning>
|
||||||
|
|
||||||
2. In postmark you need to create thre templates for each locale with the following alias:
|
2. In postmark you need to create three templates for each locale with the following alias:
|
||||||
|
|
||||||
- $locale.email-change
|
- $locale.email-confirm-change
|
||||||
- $locale.email-verify
|
- $locale.email-verify
|
||||||
- $locale.password-reset
|
- $locale.password-reset
|
||||||
|
|
||||||
For instance:
|
For instance:
|
||||||
|
|
||||||
- en.email-change
|
- en.email-confirm-change
|
||||||
- en.email-verify
|
- en.email-verify
|
||||||
- en.password-reset
|
- en.password-reset
|
||||||
- se.email-change
|
- se.email-confirm-change
|
||||||
- se.email-verify
|
- se.email-verify
|
||||||
- se.password-reset
|
- se.password-reset
|
||||||
|
|
||||||
|
Additionally, if you want to use the passwordless sign-in or OTP sign-in emails, you need to create the following templates as well:
|
||||||
|
|
||||||
|
- $locale.signin-passwordless
|
||||||
|
- $locale.signin-otp
|
||||||
|
|
||||||
After these two steps have been completed, the Auth service will leverage these templates instead of the ones described in the previous section.
|
After these two steps have been completed, the Auth service will leverage these templates instead of the ones described in the previous section.
|
||||||
|
|
||||||
<Note>
|
<Note>
|
||||||
|
|||||||
@@ -1308,7 +1308,7 @@ components:
|
|||||||
BearerAuthElevated:
|
BearerAuthElevated:
|
||||||
type: http
|
type: http
|
||||||
scheme: bearer
|
scheme: bearer
|
||||||
description: "Bearer authentication that requires elevated permissions. Used for sensitive operations that may require additional security measures such as recent authentication. For details see https://docs.nhost.io/guides/auth/elevated-permissions"
|
description: "Bearer authentication that requires elevated permissions. Used for sensitive operations that may require additional security measures such as recent authentication. For details see https://docs.nhost.io/products/auth/elevated-permissions"
|
||||||
|
|
||||||
schemas:
|
schemas:
|
||||||
AttestationFormat:
|
AttestationFormat:
|
||||||
|
|||||||
@@ -69,6 +69,51 @@ Error.constructor
|
|||||||
|
|
||||||
# Interfaces
|
# Interfaces
|
||||||
|
|
||||||
|
## AdminSessionOptions
|
||||||
|
|
||||||
|
Configuration options for admin session middleware
|
||||||
|
|
||||||
|
### Properties
|
||||||
|
|
||||||
|
#### adminSecret
|
||||||
|
|
||||||
|
```ts
|
||||||
|
adminSecret: string
|
||||||
|
```
|
||||||
|
|
||||||
|
Hasura admin secret for elevated permissions (sets x-hasura-admin-secret header)
|
||||||
|
|
||||||
|
#### role?
|
||||||
|
|
||||||
|
```ts
|
||||||
|
optional role: string;
|
||||||
|
```
|
||||||
|
|
||||||
|
Hasura role to use for the request (sets x-hasura-role header)
|
||||||
|
|
||||||
|
#### sessionVariables?
|
||||||
|
|
||||||
|
```ts
|
||||||
|
optional sessionVariables: Record<string, string>;
|
||||||
|
```
|
||||||
|
|
||||||
|
Additional Hasura session variables to attach to requests.
|
||||||
|
Keys will be automatically prefixed with 'x-hasura-' if not already present.
|
||||||
|
|
||||||
|
##### Example
|
||||||
|
|
||||||
|
```ts
|
||||||
|
{
|
||||||
|
'user-id': '123',
|
||||||
|
'org-id': '456'
|
||||||
|
}
|
||||||
|
// Results in headers:
|
||||||
|
// x-hasura-user-id: 123
|
||||||
|
// x-hasura-org-id: 456
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## FetchResponse<T>
|
## FetchResponse<T>
|
||||||
|
|
||||||
Interface representing a structured API response.
|
Interface representing a structured API response.
|
||||||
@@ -301,3 +346,151 @@ that create or invalidate sessions.
|
|||||||
[`ChainFunction`](#chainfunction)
|
[`ChainFunction`](#chainfunction)
|
||||||
|
|
||||||
A middleware function that can be used in the fetch chain
|
A middleware function that can be used in the fetch chain
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## withAdminSessionMiddleware()
|
||||||
|
|
||||||
|
```ts
|
||||||
|
function withAdminSessionMiddleware(options: AdminSessionOptions): ChainFunction
|
||||||
|
```
|
||||||
|
|
||||||
|
Creates a fetch middleware that attaches the Hasura admin secret and optional session variables to requests.
|
||||||
|
|
||||||
|
This middleware:
|
||||||
|
|
||||||
|
1. Sets the x-hasura-admin-secret header, which grants full admin access to Hasura
|
||||||
|
2. Optionally sets the x-hasura-role header if a role is provided
|
||||||
|
3. Optionally sets additional x-hasura-\* headers for custom session variables
|
||||||
|
|
||||||
|
**Security Warning**: Never use this middleware in client-side code or expose
|
||||||
|
the admin secret to end users. Admin secrets grant unrestricted access to your
|
||||||
|
entire database. This should only be used in trusted server-side environments.
|
||||||
|
|
||||||
|
The middleware preserves request-specific headers when they conflict with the
|
||||||
|
admin session configuration.
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | --------------------------------------------- | ------------------------------------------------------------------------- |
|
||||||
|
| `options` | [`AdminSessionOptions`](#adminsessionoptions) | Admin session options including admin secret, role, and session variables |
|
||||||
|
|
||||||
|
### Returns
|
||||||
|
|
||||||
|
[`ChainFunction`](#chainfunction)
|
||||||
|
|
||||||
|
A middleware function that can be used in the fetch chain
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// Create middleware with admin secret only
|
||||||
|
const adminMiddleware = withAdminSessionMiddleware({
|
||||||
|
adminSecret: process.env.NHOST_ADMIN_SECRET
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create middleware with admin secret and role
|
||||||
|
const adminUserMiddleware = withAdminSessionMiddleware({
|
||||||
|
adminSecret: process.env.NHOST_ADMIN_SECRET,
|
||||||
|
role: 'user'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create middleware with admin secret, role, and custom session variables
|
||||||
|
const fullMiddleware = withAdminSessionMiddleware({
|
||||||
|
adminSecret: process.env.NHOST_ADMIN_SECRET,
|
||||||
|
role: 'user',
|
||||||
|
sessionVariables: {
|
||||||
|
'user-id': '123',
|
||||||
|
'org-id': '456'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Use with createCustomClient for an admin client
|
||||||
|
const adminClient = createCustomClient({
|
||||||
|
subdomain: 'myproject',
|
||||||
|
region: 'eu-central-1',
|
||||||
|
chainFunctions: [adminMiddleware]
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## withHeadersMiddleware()
|
||||||
|
|
||||||
|
```ts
|
||||||
|
function withHeadersMiddleware(defaultHeaders: HeadersInit): ChainFunction
|
||||||
|
```
|
||||||
|
|
||||||
|
Creates a fetch middleware that attaches default headers to requests.
|
||||||
|
|
||||||
|
This middleware:
|
||||||
|
|
||||||
|
1. Merges default headers with request-specific headers
|
||||||
|
2. Preserves request-specific headers when they conflict with defaults
|
||||||
|
|
||||||
|
The middleware ensures consistent headers across requests while allowing
|
||||||
|
individual requests to override defaults as needed.
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| ---------------- | ------------- | ----------------------------------------- |
|
||||||
|
| `defaultHeaders` | `HeadersInit` | Default headers to attach to all requests |
|
||||||
|
|
||||||
|
### Returns
|
||||||
|
|
||||||
|
[`ChainFunction`](#chainfunction)
|
||||||
|
|
||||||
|
A middleware function that can be used in the fetch chain
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## withRoleMiddleware()
|
||||||
|
|
||||||
|
```ts
|
||||||
|
function withRoleMiddleware(role: string): ChainFunction
|
||||||
|
```
|
||||||
|
|
||||||
|
Creates a fetch middleware that sets the Hasura role header.
|
||||||
|
|
||||||
|
This middleware sets the x-hasura-role header for all requests, allowing
|
||||||
|
you to specify which role's permissions should be used. This works with
|
||||||
|
authenticated sessions where the user has access to the specified role.
|
||||||
|
|
||||||
|
Unlike `withAdminSessionMiddleware`, this does not bypass permission rules
|
||||||
|
but instead uses the permission rules defined for the specified role.
|
||||||
|
|
||||||
|
The middleware preserves request-specific headers when they conflict with
|
||||||
|
the role configuration.
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | -------- | ----------------------------------- |
|
||||||
|
| `role` | `string` | The Hasura role to use for requests |
|
||||||
|
|
||||||
|
### Returns
|
||||||
|
|
||||||
|
[`ChainFunction`](#chainfunction)
|
||||||
|
|
||||||
|
A middleware function that can be used in the fetch chain
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// Use with createClient to default all requests to a specific role
|
||||||
|
const nhost = createClient({
|
||||||
|
subdomain: 'myproject',
|
||||||
|
region: 'eu-central-1',
|
||||||
|
chainFunctions: [withRoleMiddleware('moderator')]
|
||||||
|
})
|
||||||
|
|
||||||
|
// Use with createServerClient for server-side requests
|
||||||
|
const serverNhost = createServerClient({
|
||||||
|
subdomain: 'myproject',
|
||||||
|
region: 'eu-central-1',
|
||||||
|
storage: myServerStorage,
|
||||||
|
chainFunctions: [withRoleMiddleware('moderator')]
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ console.log(JSON.stringify(uplFilesResp, null, 2))
|
|||||||
// "updatedAt": "2025-05-09T17:26:04.589692+00:00",
|
// "updatedAt": "2025-05-09T17:26:04.589692+00:00",
|
||||||
// "isUploaded": true,
|
// "isUploaded": true,
|
||||||
// "mimeType": "text/plain",
|
// "mimeType": "text/plain",
|
||||||
// "uploadedByUserId": "",
|
// "uploadedByUserId": "3357aada-b6c7-4af1-9655-1307ca2883a2",
|
||||||
// "metadata": null
|
// "metadata": null
|
||||||
// },
|
// },
|
||||||
// {
|
// {
|
||||||
@@ -67,7 +67,7 @@ console.log(JSON.stringify(uplFilesResp, null, 2))
|
|||||||
// "updatedAt": "2025-05-09T17:26:04.596831+00:00",
|
// "updatedAt": "2025-05-09T17:26:04.596831+00:00",
|
||||||
// "isUploaded": true,
|
// "isUploaded": true,
|
||||||
// "mimeType": "text/plain",
|
// "mimeType": "text/plain",
|
||||||
// "uploadedByUserId": "",
|
// "uploadedByUserId": "3357aada-b6c7-4af1-9655-1307ca2883a2",
|
||||||
// "metadata": null
|
// "metadata": null
|
||||||
// }
|
// }
|
||||||
// ]
|
// ]
|
||||||
@@ -125,6 +125,77 @@ console.log(JSON.stringify(funcResp.body, null, 2))
|
|||||||
// }
|
// }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Creating an admin client
|
||||||
|
|
||||||
|
You can also create an admin client if needed. This client will have admin access to the database
|
||||||
|
and will bypass permissions. Additionally, it can impersonate users and set any role or session
|
||||||
|
variable.
|
||||||
|
|
||||||
|
IMPORTANT!!! Keep your admin secret safe and never expose it in client-side code.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const nhost = createNhostClient({
|
||||||
|
subdomain,
|
||||||
|
region,
|
||||||
|
configure: [
|
||||||
|
withAdminSession({
|
||||||
|
adminSecret: 'nhost-admin-secret',
|
||||||
|
role: 'user',
|
||||||
|
sessionVariables: {
|
||||||
|
'user-id': '54058C42-51F7-4B37-8B69-C89A841D2221'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
// upload a couple of files
|
||||||
|
const uplFilesResp = await nhost.storage.uploadFiles({
|
||||||
|
'file[]': [
|
||||||
|
new File(['test1'], 'file-1', { type: 'text/plain' }),
|
||||||
|
new File(['test2 is larger'], 'file-2', { type: 'text/plain' })
|
||||||
|
]
|
||||||
|
})
|
||||||
|
console.log(JSON.stringify(uplFilesResp, null, 2))
|
||||||
|
// {
|
||||||
|
// "data": {
|
||||||
|
// "processedFiles": [
|
||||||
|
// {
|
||||||
|
// "id": "c0e83185-0ce5-435c-bd46-9841adc30699",
|
||||||
|
// "name": "file-1",
|
||||||
|
// "size": 5,
|
||||||
|
// "bucketId": "default",
|
||||||
|
// "etag": "\"5a105e8b9d40e1329780d62ea2265d8a\"",
|
||||||
|
// "createdAt": "2025-05-09T17:26:04.579839+00:00",
|
||||||
|
// "updatedAt": "2025-05-09T17:26:04.589692+00:00",
|
||||||
|
// "isUploaded": true,
|
||||||
|
// "mimeType": "text/plain",
|
||||||
|
// "uploadedByUserId": "54058c42-51f7-4b37-8b69-c89a841d2221",
|
||||||
|
// "metadata": null
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": "3f189004-21fd-42d0-be1d-1ead021ab167",
|
||||||
|
// "name": "file-2",
|
||||||
|
// "size": 15,
|
||||||
|
// "bucketId": "default",
|
||||||
|
// "etag": "\"302e888c5e289fe6b02115b748771ee9\"",
|
||||||
|
// "createdAt": "2025-05-09T17:26:04.59245+00:00",
|
||||||
|
// "updatedAt": "2025-05-09T17:26:04.596831+00:00",
|
||||||
|
// "isUploaded": true,
|
||||||
|
// "mimeType": "text/plain",
|
||||||
|
// "uploadedByUserId": "54058c42-51f7-4b37-8b69-c89a841d2221",
|
||||||
|
// "metadata": null
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// },
|
||||||
|
// "status": 201,
|
||||||
|
// "headers": {
|
||||||
|
// "content-length": "644",
|
||||||
|
// "content-type": "application/json; charset=utf-8",
|
||||||
|
// "date": "Fri, 09 May 2025 17:26:04 GMT"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
```
|
||||||
|
|
||||||
# Interfaces
|
# Interfaces
|
||||||
|
|
||||||
## NhostClient
|
## NhostClient
|
||||||
@@ -287,6 +358,15 @@ optional authUrl: string;
|
|||||||
|
|
||||||
Complete base URL for the auth service (overrides subdomain/region)
|
Complete base URL for the auth service (overrides subdomain/region)
|
||||||
|
|
||||||
|
#### configure?
|
||||||
|
|
||||||
|
```ts
|
||||||
|
optional configure: ClientConfigurationFn[];
|
||||||
|
```
|
||||||
|
|
||||||
|
Configuration functions to be applied to the client after initialization.
|
||||||
|
These functions receive all clients and can attach middleware or perform other setup.
|
||||||
|
|
||||||
#### functionsUrl?
|
#### functionsUrl?
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
@@ -360,6 +440,19 @@ Complete base URL for the auth service (overrides subdomain/region)
|
|||||||
|
|
||||||
[`NhostClientOptions`](#nhostclientoptions).[`authUrl`](#authurl)
|
[`NhostClientOptions`](#nhostclientoptions).[`authUrl`](#authurl)
|
||||||
|
|
||||||
|
#### configure?
|
||||||
|
|
||||||
|
```ts
|
||||||
|
optional configure: ClientConfigurationFn[];
|
||||||
|
```
|
||||||
|
|
||||||
|
Configuration functions to be applied to the client after initialization.
|
||||||
|
These functions receive all clients and can attach middleware or perform other setup.
|
||||||
|
|
||||||
|
##### Inherited from
|
||||||
|
|
||||||
|
[`NhostClientOptions`](#nhostclientoptions).[`configure`](#configure)
|
||||||
|
|
||||||
#### functionsUrl?
|
#### functionsUrl?
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
@@ -434,6 +527,55 @@ Nhost project subdomain (e.g., 'abcdefgh'). Used to construct the base URL for s
|
|||||||
|
|
||||||
[`NhostClientOptions`](#nhostclientoptions).[`subdomain`](#subdomain)
|
[`NhostClientOptions`](#nhostclientoptions).[`subdomain`](#subdomain)
|
||||||
|
|
||||||
|
# Type Aliases
|
||||||
|
|
||||||
|
## ClientConfigurationFn()
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type ClientConfigurationFn = (clients: object) => void
|
||||||
|
```
|
||||||
|
|
||||||
|
Configuration function that receives all clients and can configure them
|
||||||
|
(e.g., by attaching middleware, setting up interceptors, etc.)
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
| Parameter | Type |
|
||||||
|
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
| `clients` | \{ `auth`: [`Client`](./auth#client); `functions`: [`Client`](./functions#client); `graphql`: [`Client`](./graphql#client); `sessionStorage`: [`SessionStorage`](./session#sessionstorage); `storage`: [`Client`](./storage#client); \} |
|
||||||
|
| `clients.auth` | [`Client`](./auth#client) |
|
||||||
|
| `clients.functions` | [`Client`](./functions#client) |
|
||||||
|
| `clients.graphql` | [`Client`](./graphql#client) |
|
||||||
|
| `clients.sessionStorage` | [`SessionStorage`](./session#sessionstorage) |
|
||||||
|
| `clients.storage` | [`Client`](./storage#client) |
|
||||||
|
|
||||||
|
### Returns
|
||||||
|
|
||||||
|
`void`
|
||||||
|
|
||||||
|
# Variables
|
||||||
|
|
||||||
|
## withClientSideSessionMiddleware
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const withClientSideSessionMiddleware: ClientConfigurationFn
|
||||||
|
```
|
||||||
|
|
||||||
|
Built-in configuration for client-side applications.
|
||||||
|
Includes automatic session refresh, token attachment, and session updates.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## withServerSideSessionMiddleware
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const withServerSideSessionMiddleware: ClientConfigurationFn
|
||||||
|
```
|
||||||
|
|
||||||
|
Built-in configuration for server-side applications.
|
||||||
|
Includes token attachment and session updates, but NOT automatic session refresh
|
||||||
|
to prevent race conditions in server contexts.
|
||||||
|
|
||||||
# Functions
|
# Functions
|
||||||
|
|
||||||
## createClient()
|
## createClient()
|
||||||
@@ -495,6 +637,72 @@ const nhost = createClient({
|
|||||||
secure: import.meta.env.ENVIRONMENT === 'production'
|
secure: import.meta.env.ENVIRONMENT === 'production'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Create client with additional custom middleware
|
||||||
|
const nhost = createClient({
|
||||||
|
subdomain: 'abcdefgh',
|
||||||
|
region: 'eu-central-1',
|
||||||
|
configure: [customLoggingMiddleware]
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## createNhostClient()
|
||||||
|
|
||||||
|
```ts
|
||||||
|
function createNhostClient(options: NhostClientOptions): NhostClient
|
||||||
|
```
|
||||||
|
|
||||||
|
Creates and configures a new Nhost client instance with custom configuration.
|
||||||
|
|
||||||
|
This is the main factory function for creating Nhost clients. It instantiates
|
||||||
|
all service clients (auth, storage, graphql, functions) and applies the provided
|
||||||
|
configuration functions to set up middleware and other customizations.
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --------- | ------------------------------------------- | ------------------------------------ |
|
||||||
|
| `options` | [`NhostClientOptions`](#nhostclientoptions) | Configuration options for the client |
|
||||||
|
|
||||||
|
### Returns
|
||||||
|
|
||||||
|
[`NhostClient`](#nhostclient)
|
||||||
|
|
||||||
|
A configured Nhost client
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// Create a basic client with no middleware
|
||||||
|
const nhost = createNhostClient({
|
||||||
|
subdomain: 'abcdefgh',
|
||||||
|
region: 'eu-central-1',
|
||||||
|
configure: []
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create a client with custom configuration
|
||||||
|
const nhost = createNhostClient({
|
||||||
|
subdomain: 'abcdefgh',
|
||||||
|
region: 'eu-central-1',
|
||||||
|
configure: [withClientSideSessionMiddleware, withChainFunctions([customLoggingMiddleware])]
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create an admin client
|
||||||
|
const nhost = createNhostClient({
|
||||||
|
subdomain,
|
||||||
|
region,
|
||||||
|
configure: [
|
||||||
|
withAdminSession({
|
||||||
|
adminSecret: 'nhost-admin-secret',
|
||||||
|
role: 'user',
|
||||||
|
sessionVariables: {
|
||||||
|
'user-id': '54058C42-51F7-4B37-8B69-C89A841D2221'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -623,6 +831,14 @@ const nhostClientFromCookies = (req: Request) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Example with additional custom middleware
|
||||||
|
const nhost = createServerClient({
|
||||||
|
region: process.env['NHOST_REGION'] || 'local',
|
||||||
|
subdomain: process.env['NHOST_SUBDOMAIN'] || 'local',
|
||||||
|
storage: myStorage,
|
||||||
|
configure: [customLoggingMiddleware]
|
||||||
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -631,7 +847,7 @@ const nhostClientFromCookies = (req: Request) => {
|
|||||||
|
|
||||||
```ts
|
```ts
|
||||||
function generateServiceUrl(
|
function generateServiceUrl(
|
||||||
serviceType: 'storage' | 'auth' | 'graphql' | 'functions',
|
serviceType: 'auth' | 'storage' | 'graphql' | 'functions',
|
||||||
subdomain?: string,
|
subdomain?: string,
|
||||||
region?: string,
|
region?: string,
|
||||||
customUrl?: string
|
customUrl?: string
|
||||||
@@ -644,7 +860,7 @@ Generates a base URL for a Nhost service based on configuration
|
|||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| ------------- | ------------------------------------------------------- | --------------------------------------------------- |
|
| ------------- | ------------------------------------------------------- | --------------------------------------------------- |
|
||||||
| `serviceType` | `"storage"` \| `"auth"` \| `"graphql"` \| `"functions"` | Type of service (auth, storage, graphql, functions) |
|
| `serviceType` | `"auth"` \| `"storage"` \| `"graphql"` \| `"functions"` | Type of service (auth, storage, graphql, functions) |
|
||||||
| `subdomain?` | `string` | Nhost project subdomain |
|
| `subdomain?` | `string` | Nhost project subdomain |
|
||||||
| `region?` | `string` | Nhost region |
|
| `region?` | `string` | Nhost region |
|
||||||
| `customUrl?` | `string` | Custom URL override if provided |
|
| `customUrl?` | `string` | Custom URL override if provided |
|
||||||
@@ -654,3 +870,29 @@ Generates a base URL for a Nhost service based on configuration
|
|||||||
`string`
|
`string`
|
||||||
|
|
||||||
The base URL for the service
|
The base URL for the service
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## withAdminSession()
|
||||||
|
|
||||||
|
```ts
|
||||||
|
function withAdminSession(adminSession: AdminSessionOptions): ClientConfigurationFn
|
||||||
|
```
|
||||||
|
|
||||||
|
Configuration for admin clients with elevated privileges.
|
||||||
|
Applies admin session middleware to storage, graphql, and functions clients only.
|
||||||
|
|
||||||
|
**Security Warning**: Never use this in client-side code. Admin secrets grant
|
||||||
|
unrestricted access to your entire database.
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| -------------- | ------------------------------------------------------ | ------------------------------------------------------------------------- |
|
||||||
|
| `adminSession` | [`AdminSessionOptions`](./fetch#adminsessionoptions) | Admin session options including admin secret, role, and session variables |
|
||||||
|
|
||||||
|
### Returns
|
||||||
|
|
||||||
|
[`ClientConfigurationFn`](#clientconfigurationfn)
|
||||||
|
|
||||||
|
Configuration function that sets up admin middleware
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
table:
|
|
||||||
name: attachments
|
|
||||||
schema: public
|
|
||||||
configuration:
|
|
||||||
column_config:
|
|
||||||
task_id:
|
|
||||||
custom_name: taskID
|
|
||||||
custom_column_names:
|
|
||||||
task_id: taskID
|
|
||||||
custom_root_fields:
|
|
||||||
delete: deleteAttachments
|
|
||||||
delete_by_pk: deleteAttachment
|
|
||||||
insert: insertAttachments
|
|
||||||
insert_one: insertAttachment
|
|
||||||
select: attachments
|
|
||||||
select_aggregate: attachmentsAggregate
|
|
||||||
select_by_pk: attachment
|
|
||||||
select_stream: attachmentsStream
|
|
||||||
update: updateAttachments
|
|
||||||
update_by_pk: updateAttachment
|
|
||||||
update_many: updateAttachmentsMany
|
|
||||||
object_relationships:
|
|
||||||
- name: file
|
|
||||||
using:
|
|
||||||
foreign_key_constraint_on: file_id
|
|
||||||
- name: task
|
|
||||||
using:
|
|
||||||
foreign_key_constraint_on: task_id
|
|
||||||
insert_permissions:
|
|
||||||
- role: user
|
|
||||||
permission:
|
|
||||||
check:
|
|
||||||
_and:
|
|
||||||
- file:
|
|
||||||
uploaded_by_user_id:
|
|
||||||
_eq: X-Hasura-User-Id
|
|
||||||
- task:
|
|
||||||
user_id:
|
|
||||||
_eq: X-Hasura-User-Id
|
|
||||||
columns:
|
|
||||||
- file_id
|
|
||||||
- task_id
|
|
||||||
comment: ""
|
|
||||||
select_permissions:
|
|
||||||
- role: user
|
|
||||||
permission:
|
|
||||||
columns:
|
|
||||||
- file_id
|
|
||||||
- task_id
|
|
||||||
filter:
|
|
||||||
_and:
|
|
||||||
- file:
|
|
||||||
uploaded_by_user_id:
|
|
||||||
_eq: X-Hasura-User-Id
|
|
||||||
- task:
|
|
||||||
user_id:
|
|
||||||
_eq: X-Hasura-User-Id
|
|
||||||
comment: ""
|
|
||||||
delete_permissions:
|
|
||||||
- role: user
|
|
||||||
permission:
|
|
||||||
filter:
|
|
||||||
_and:
|
|
||||||
- file:
|
|
||||||
uploaded_by_user_id:
|
|
||||||
_eq: X-Hasura-User-Id
|
|
||||||
- task:
|
|
||||||
user_id:
|
|
||||||
_eq: X-Hasura-User-Id
|
|
||||||
comment: ""
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
table:
|
|
||||||
name: comments
|
|
||||||
schema: public
|
|
||||||
configuration:
|
|
||||||
column_config:
|
|
||||||
comment:
|
|
||||||
custom_name: comment
|
|
||||||
created_at:
|
|
||||||
custom_name: createdAt
|
|
||||||
id:
|
|
||||||
custom_name: id
|
|
||||||
ninja_turtle_id:
|
|
||||||
custom_name: ninjaTurtleId
|
|
||||||
updated_at:
|
|
||||||
custom_name: updatedAt
|
|
||||||
user_id:
|
|
||||||
custom_name: userId
|
|
||||||
custom_column_names:
|
|
||||||
comment: comment
|
|
||||||
created_at: createdAt
|
|
||||||
id: id
|
|
||||||
ninja_turtle_id: ninjaTurtleId
|
|
||||||
updated_at: updatedAt
|
|
||||||
user_id: userId
|
|
||||||
custom_name: comments
|
|
||||||
custom_root_fields:
|
|
||||||
delete: deleteComments
|
|
||||||
delete_by_pk: deleteComment
|
|
||||||
insert: insertComments
|
|
||||||
insert_one: insertComment
|
|
||||||
select: comments
|
|
||||||
select_aggregate: commentsAggregate
|
|
||||||
select_by_pk: comment
|
|
||||||
select_stream: commentsStream
|
|
||||||
update: updateComments
|
|
||||||
update_by_pk: updateComment
|
|
||||||
update_many: updateCommentsMany
|
|
||||||
object_relationships:
|
|
||||||
- name: ninjaTurtle
|
|
||||||
using:
|
|
||||||
foreign_key_constraint_on: ninja_turtle_id
|
|
||||||
- name: user
|
|
||||||
using:
|
|
||||||
foreign_key_constraint_on: user_id
|
|
||||||
insert_permissions:
|
|
||||||
- role: user
|
|
||||||
permission:
|
|
||||||
check:
|
|
||||||
user_id:
|
|
||||||
_eq: X-Hasura-User-Id
|
|
||||||
set:
|
|
||||||
user_id: x-hasura-User-Id
|
|
||||||
columns:
|
|
||||||
- ninja_turtle_id
|
|
||||||
- comment
|
|
||||||
comment: Allow users to add comments, automatically setting their user_id
|
|
||||||
select_permissions:
|
|
||||||
- role: user
|
|
||||||
permission:
|
|
||||||
columns:
|
|
||||||
- id
|
|
||||||
- created_at
|
|
||||||
- updated_at
|
|
||||||
- ninja_turtle_id
|
|
||||||
- comment
|
|
||||||
- user_id
|
|
||||||
filter: {}
|
|
||||||
allow_aggregations: true
|
|
||||||
comment: Allow users to view all comments
|
|
||||||
update_permissions:
|
|
||||||
- role: user
|
|
||||||
permission:
|
|
||||||
columns:
|
|
||||||
- comment
|
|
||||||
filter:
|
|
||||||
user_id:
|
|
||||||
_eq: X-Hasura-User-Id
|
|
||||||
check: {}
|
|
||||||
comment: Allow users to update only their own comments
|
|
||||||
delete_permissions:
|
|
||||||
- role: user
|
|
||||||
permission:
|
|
||||||
filter:
|
|
||||||
user_id:
|
|
||||||
_eq: X-Hasura-User-Id
|
|
||||||
comment: Allow users to delete only their own comments
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
table:
|
|
||||||
name: movies
|
|
||||||
schema: public
|
|
||||||
select_permissions:
|
|
||||||
- role: public
|
|
||||||
permission:
|
|
||||||
columns:
|
|
||||||
- id
|
|
||||||
- title
|
|
||||||
- director
|
|
||||||
- release_year
|
|
||||||
- genre
|
|
||||||
- rating
|
|
||||||
- created_at
|
|
||||||
- updated_at
|
|
||||||
filter: {}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
table:
|
|
||||||
name: ninja_turtles
|
|
||||||
schema: public
|
|
||||||
configuration:
|
|
||||||
column_config:
|
|
||||||
created_at:
|
|
||||||
custom_name: createdAt
|
|
||||||
id:
|
|
||||||
custom_name: id
|
|
||||||
name:
|
|
||||||
custom_name: name
|
|
||||||
updated_at:
|
|
||||||
custom_name: updatedAt
|
|
||||||
custom_column_names:
|
|
||||||
created_at: createdAt
|
|
||||||
id: id
|
|
||||||
name: name
|
|
||||||
updated_at: updatedAt
|
|
||||||
custom_name: ninjaTurtles
|
|
||||||
custom_root_fields:
|
|
||||||
delete: deleteNinjaTurtles
|
|
||||||
delete_by_pk: deleteNinjaTurtle
|
|
||||||
insert: insertNinjaTurtles
|
|
||||||
insert_one: insertNinjaTurtle
|
|
||||||
select: ninjaTurtles
|
|
||||||
select_aggregate: ninjaTurtlesAggregate
|
|
||||||
select_by_pk: ninjaTurtle
|
|
||||||
select_stream: ninjaTurtlesStream
|
|
||||||
update: updateNinjaTurtles
|
|
||||||
update_by_pk: updateNinjaTurtle
|
|
||||||
update_many: updateNinjaTurtlesMany
|
|
||||||
array_relationships:
|
|
||||||
- name: comments
|
|
||||||
using:
|
|
||||||
foreign_key_constraint_on:
|
|
||||||
column: ninja_turtle_id
|
|
||||||
table:
|
|
||||||
name: comments
|
|
||||||
schema: public
|
|
||||||
select_permissions:
|
|
||||||
- role: user
|
|
||||||
permission:
|
|
||||||
columns:
|
|
||||||
- created_at
|
|
||||||
- description
|
|
||||||
- id
|
|
||||||
- name
|
|
||||||
- updated_at
|
|
||||||
filter: {}
|
|
||||||
comment: ""
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
table:
|
|
||||||
name: tasks
|
|
||||||
schema: public
|
|
||||||
configuration:
|
|
||||||
column_config:
|
|
||||||
created_at:
|
|
||||||
custom_name: createdAt
|
|
||||||
updated_at:
|
|
||||||
custom_name: updatedAt
|
|
||||||
user_id:
|
|
||||||
custom_name: userID
|
|
||||||
custom_column_names:
|
|
||||||
created_at: createdAt
|
|
||||||
updated_at: updatedAt
|
|
||||||
user_id: userID
|
|
||||||
custom_root_fields:
|
|
||||||
delete: deleteTasks
|
|
||||||
delete_by_pk: deleteTask
|
|
||||||
insert: insertTasks
|
|
||||||
insert_one: insertTask
|
|
||||||
select: tasks
|
|
||||||
select_aggregate: tasksAggregate
|
|
||||||
select_by_pk: task
|
|
||||||
select_stream: tasksStream
|
|
||||||
update: updateTasks
|
|
||||||
update_by_pk: updateTask
|
|
||||||
update_many: updateTasksMany
|
|
||||||
insert_permissions:
|
|
||||||
- role: user
|
|
||||||
permission:
|
|
||||||
check:
|
|
||||||
user_id:
|
|
||||||
_eq: X-Hasura-User-Id
|
|
||||||
set:
|
|
||||||
user_id: x-hasura-User-Id
|
|
||||||
columns:
|
|
||||||
- completed
|
|
||||||
- description
|
|
||||||
- title
|
|
||||||
comment: ""
|
|
||||||
select_permissions:
|
|
||||||
- role: user
|
|
||||||
permission:
|
|
||||||
columns:
|
|
||||||
- completed
|
|
||||||
- description
|
|
||||||
- title
|
|
||||||
- created_at
|
|
||||||
- updated_at
|
|
||||||
- id
|
|
||||||
- user_id
|
|
||||||
filter:
|
|
||||||
user_id:
|
|
||||||
_eq: X-Hasura-User-Id
|
|
||||||
comment: ""
|
|
||||||
update_permissions:
|
|
||||||
- role: user
|
|
||||||
permission:
|
|
||||||
columns:
|
|
||||||
- completed
|
|
||||||
- description
|
|
||||||
- title
|
|
||||||
filter: {}
|
|
||||||
check:
|
|
||||||
user_id:
|
|
||||||
_eq: X-Hasura-User-Id
|
|
||||||
comment: ""
|
|
||||||
delete_permissions:
|
|
||||||
- role: user
|
|
||||||
permission:
|
|
||||||
filter:
|
|
||||||
user_id:
|
|
||||||
_eq: X-Hasura-User-Id
|
|
||||||
comment: ""
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
table:
|
||||||
|
name: todos
|
||||||
|
schema: public
|
||||||
|
insert_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
check: {}
|
||||||
|
set:
|
||||||
|
user_id: X-Hasura-User-Id
|
||||||
|
columns:
|
||||||
|
- created_at
|
||||||
|
- updated_at
|
||||||
|
- title
|
||||||
|
- details
|
||||||
|
- completed
|
||||||
|
- user_id
|
||||||
|
select_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- id
|
||||||
|
- created_at
|
||||||
|
- updated_at
|
||||||
|
- title
|
||||||
|
- details
|
||||||
|
- completed
|
||||||
|
- user_id
|
||||||
|
filter:
|
||||||
|
user_id:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
update_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- title
|
||||||
|
- details
|
||||||
|
- completed
|
||||||
|
filter:
|
||||||
|
user_id:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
check: null
|
||||||
|
delete_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
filter:
|
||||||
|
user_id:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
@@ -57,7 +57,7 @@ insert_permissions:
|
|||||||
permission:
|
permission:
|
||||||
check:
|
check:
|
||||||
bucket_id:
|
bucket_id:
|
||||||
_eq: personal
|
_eq: default
|
||||||
set:
|
set:
|
||||||
uploaded_by_user_id: X-Hasura-User-Id
|
uploaded_by_user_id: X-Hasura-User-Id
|
||||||
columns:
|
columns:
|
||||||
@@ -84,7 +84,7 @@ select_permissions:
|
|||||||
filter:
|
filter:
|
||||||
_and:
|
_and:
|
||||||
- bucket_id:
|
- bucket_id:
|
||||||
_eq: personal
|
_eq: default
|
||||||
- uploaded_by_user_id:
|
- uploaded_by_user_id:
|
||||||
_eq: X-Hasura-User-Id
|
_eq: X-Hasura-User-Id
|
||||||
delete_permissions:
|
delete_permissions:
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
DROP TABLE "public"."tasks";
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
CREATE TABLE "public"."tasks" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "title" text NOT NULL, "description" text NOT NULL, "completed" boolean NOT NULL DEFAULT false, "user_id" uuid NOT NULL, PRIMARY KEY ("id") , FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id") ON UPDATE cascade ON DELETE cascade);
|
|
||||||
CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"()
|
|
||||||
RETURNS TRIGGER AS $$
|
|
||||||
DECLARE
|
|
||||||
_new record;
|
|
||||||
BEGIN
|
|
||||||
_new := NEW;
|
|
||||||
_new."updated_at" = NOW();
|
|
||||||
RETURN _new;
|
|
||||||
END;
|
|
||||||
$$ LANGUAGE plpgsql;
|
|
||||||
CREATE TRIGGER "set_public_tasks_updated_at"
|
|
||||||
BEFORE UPDATE ON "public"."tasks"
|
|
||||||
FOR EACH ROW
|
|
||||||
EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"();
|
|
||||||
COMMENT ON TRIGGER "set_public_tasks_updated_at" ON "public"."tasks"
|
|
||||||
IS 'trigger to set value of column "updated_at" to current timestamp on row update';
|
|
||||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
DROP TABLE "public"."attachments";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
CREATE TABLE "public"."attachments" ("task_id" uuid NOT NULL, "file_id" uuid NOT NULL, PRIMARY KEY ("task_id","file_id") , FOREIGN KEY ("task_id") REFERENCES "public"."tasks"("id") ON UPDATE cascade ON DELETE cascade, FOREIGN KEY ("file_id") REFERENCES "storage"."files"("id") ON UPDATE restrict ON DELETE restrict);
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
DROP TABLE public.ninja_turtles;
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
CREATE TABLE public.ninja_turtles (
|
|
||||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
||||||
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
|
|
||||||
updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
|
|
||||||
name TEXT NOT NULL
|
|
||||||
);
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
DROP TABLE public.comments;
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
CREATE TABLE public.comments (
|
|
||||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
||||||
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
|
|
||||||
updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
|
|
||||||
ninja_turtle_id UUID NOT NULL REFERENCES public.ninja_turtles(id) ON DELETE CASCADE,
|
|
||||||
comment TEXT NOT NULL,
|
|
||||||
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE
|
|
||||||
);
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
DELETE FROM public.ninja_turtles WHERE name IN ('Leonardo', 'Raphael', 'Donatello', 'Michelangelo');
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
INSERT INTO public.ninja_turtles (id, name, created_at, updated_at) VALUES
|
|
||||||
(gen_random_uuid(), 'Leonardo', NOW(), NOW()),
|
|
||||||
(gen_random_uuid(), 'Raphael', NOW(), NOW()),
|
|
||||||
(gen_random_uuid(), 'Donatello', NOW(), NOW()),
|
|
||||||
(gen_random_uuid(), 'Michelangelo', NOW(), NOW());
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
ALTER TABLE public.ninja_turtles DROP COLUMN description;
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
ALTER TABLE public.ninja_turtles ADD COLUMN description TEXT;
|
|
||||||
UPDATE public.ninja_turtles SET description = 'Leader of the team who wears a blue mask and uses twin katana blades. Known for his strategic mind and unwavering discipline.' WHERE name = 'Leonardo';
|
|
||||||
UPDATE public.ninja_turtles SET description = 'Hot-headed member who wears a red mask and fights with twin sai. Known for his strength, aggression, and intense loyalty to his family.' WHERE name = 'Raphael';
|
|
||||||
UPDATE public.ninja_turtles SET description = 'Technical genius who wears a purple mask and wields a bo staff. Known for his intelligence, inventions, and problem-solving abilities.' WHERE name = 'Donatello';
|
|
||||||
UPDATE public.ninja_turtles SET description = 'Fun-loving member who wears an orange mask and uses nunchaku. Known for his optimism, sense of humor, and love for pizza.' WHERE name = 'Michelangelo';
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
DROP TABLE IF EXISTS movies CASCADE;
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
CREATE TABLE movies (id UUID PRIMARY KEY DEFAULT gen_random_uuid(), title TEXT NOT NULL, director TEXT, release_year INTEGER, genre TEXT, rating DECIMAL(3,1), created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW());
|
|
||||||
INSERT INTO movies (id, title, director, release_year, genre, rating) VALUES ('3d67a6d0-bfb5-444a-9152-aea543ebd171', 'The Matrix', 'Lana Wachowski, Lilly Wachowski', 1999, 'Sci-Fi', 8.7), ('90f374db-16c1-4db5-ba55-643bf38953d3', 'Inception', 'Christopher Nolan', 2010, 'Sci-Fi', 8.8), ('900fa76c-fc79-470d-817b-4dc4412a79e8', 'The Godfather', 'Francis Ford Coppola', 1972, 'Crime', 9.2), ('2867cadd-2904-482f-b43c-f77ce8412a93', 'Pulp Fiction', 'Quentin Tarantino', 1994, 'Crime', 8.9), ('8c06c70a-872e-49a7-8770-29355dcd05c6', 'The Dark Knight', 'Christopher Nolan', 2008, 'Action', 9.0);
|
|
||||||
@@ -31,7 +31,7 @@ httpPoolSize = 100
|
|||||||
version = 22
|
version = 22
|
||||||
|
|
||||||
[auth]
|
[auth]
|
||||||
version = '0.41.1'
|
version = '0.42.2'
|
||||||
|
|
||||||
[auth.elevatedPrivileges]
|
[auth.elevatedPrivileges]
|
||||||
mode = 'disabled'
|
mode = 'disabled'
|
||||||
@@ -191,7 +191,7 @@ capacity = 1
|
|||||||
[provider]
|
[provider]
|
||||||
|
|
||||||
[storage]
|
[storage]
|
||||||
version = '0.8.0-beta3'
|
version = '0.8.2'
|
||||||
|
|
||||||
[observability]
|
[observability]
|
||||||
[observability.grafana]
|
[observability.grafana]
|
||||||
|
|||||||
131
examples/demos/react-demo/pnpm-lock.yaml
generated
131
examples/demos/react-demo/pnpm-lock.yaml
generated
@@ -32,14 +32,10 @@ importers:
|
|||||||
version: 19.1.9(@types/react@19.1.12)
|
version: 19.1.9(@types/react@19.1.12)
|
||||||
'@vitejs/plugin-react':
|
'@vitejs/plugin-react':
|
||||||
specifier: ^4.4.1
|
specifier: ^4.4.1
|
||||||
version: 4.7.0(vite@7.1.4)
|
version: 4.7.0(vite@7.1.11)
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
'@ampproject/remapping@2.3.0':
|
|
||||||
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
|
|
||||||
engines: {node: '>=6.0.0'}
|
|
||||||
|
|
||||||
'@babel/code-frame@7.27.1':
|
'@babel/code-frame@7.27.1':
|
||||||
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
|
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
@@ -48,8 +44,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==}
|
resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
'@babel/core@7.28.3':
|
'@babel/core@7.28.4':
|
||||||
resolution: {integrity: sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==}
|
resolution: {integrity: sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
'@babel/generator@7.28.3':
|
'@babel/generator@7.28.3':
|
||||||
@@ -90,12 +86,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
|
resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
'@babel/helpers@7.28.3':
|
'@babel/helpers@7.28.4':
|
||||||
resolution: {integrity: sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==}
|
resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
'@babel/parser@7.28.3':
|
'@babel/parser@7.28.4':
|
||||||
resolution: {integrity: sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==}
|
resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
@@ -115,12 +111,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
|
resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
'@babel/traverse@7.28.3':
|
'@babel/traverse@7.28.4':
|
||||||
resolution: {integrity: sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==}
|
resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
'@babel/types@7.28.2':
|
'@babel/types@7.28.4':
|
||||||
resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==}
|
resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
'@esbuild/aix-ppc64@0.25.9':
|
'@esbuild/aix-ppc64@0.25.9':
|
||||||
@@ -282,6 +278,9 @@ packages:
|
|||||||
'@jridgewell/gen-mapping@0.3.13':
|
'@jridgewell/gen-mapping@0.3.13':
|
||||||
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
|
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
|
||||||
|
|
||||||
|
'@jridgewell/remapping@2.3.5':
|
||||||
|
resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
|
||||||
|
|
||||||
'@jridgewell/resolve-uri@3.1.2':
|
'@jridgewell/resolve-uri@3.1.2':
|
||||||
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
|
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
@@ -576,8 +575,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
tinyglobby@0.2.14:
|
tinyglobby@0.2.15:
|
||||||
resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
|
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
update-browserslist-db@1.1.3:
|
update-browserslist-db@1.1.3:
|
||||||
@@ -586,8 +585,8 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
browserslist: '>= 4.21.0'
|
browserslist: '>= 4.21.0'
|
||||||
|
|
||||||
vite@7.1.4:
|
vite@7.1.11:
|
||||||
resolution: {integrity: sha512-X5QFK4SGynAeeIt+A7ZWnApdUyHYm+pzv/8/A57LqSGcI88U6R6ipOs3uCesdc6yl7nl+zNO0t8LmqAdXcQihw==}
|
resolution: {integrity: sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -631,11 +630,6 @@ packages:
|
|||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
'@ampproject/remapping@2.3.0':
|
|
||||||
dependencies:
|
|
||||||
'@jridgewell/gen-mapping': 0.3.13
|
|
||||||
'@jridgewell/trace-mapping': 0.3.30
|
|
||||||
|
|
||||||
'@babel/code-frame@7.27.1':
|
'@babel/code-frame@7.27.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/helper-validator-identifier': 7.27.1
|
'@babel/helper-validator-identifier': 7.27.1
|
||||||
@@ -644,18 +638,18 @@ snapshots:
|
|||||||
|
|
||||||
'@babel/compat-data@7.28.0': {}
|
'@babel/compat-data@7.28.0': {}
|
||||||
|
|
||||||
'@babel/core@7.28.3':
|
'@babel/core@7.28.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ampproject/remapping': 2.3.0
|
|
||||||
'@babel/code-frame': 7.27.1
|
'@babel/code-frame': 7.27.1
|
||||||
'@babel/generator': 7.28.3
|
'@babel/generator': 7.28.3
|
||||||
'@babel/helper-compilation-targets': 7.27.2
|
'@babel/helper-compilation-targets': 7.27.2
|
||||||
'@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3)
|
'@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4)
|
||||||
'@babel/helpers': 7.28.3
|
'@babel/helpers': 7.28.4
|
||||||
'@babel/parser': 7.28.3
|
'@babel/parser': 7.28.4
|
||||||
'@babel/template': 7.27.2
|
'@babel/template': 7.27.2
|
||||||
'@babel/traverse': 7.28.3
|
'@babel/traverse': 7.28.4
|
||||||
'@babel/types': 7.28.2
|
'@babel/types': 7.28.4
|
||||||
|
'@jridgewell/remapping': 2.3.5
|
||||||
convert-source-map: 2.0.0
|
convert-source-map: 2.0.0
|
||||||
debug: 4.4.1
|
debug: 4.4.1
|
||||||
gensync: 1.0.0-beta.2
|
gensync: 1.0.0-beta.2
|
||||||
@@ -666,8 +660,8 @@ snapshots:
|
|||||||
|
|
||||||
'@babel/generator@7.28.3':
|
'@babel/generator@7.28.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/parser': 7.28.3
|
'@babel/parser': 7.28.4
|
||||||
'@babel/types': 7.28.2
|
'@babel/types': 7.28.4
|
||||||
'@jridgewell/gen-mapping': 0.3.13
|
'@jridgewell/gen-mapping': 0.3.13
|
||||||
'@jridgewell/trace-mapping': 0.3.30
|
'@jridgewell/trace-mapping': 0.3.30
|
||||||
jsesc: 3.1.0
|
jsesc: 3.1.0
|
||||||
@@ -684,17 +678,17 @@ snapshots:
|
|||||||
|
|
||||||
'@babel/helper-module-imports@7.27.1':
|
'@babel/helper-module-imports@7.27.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/traverse': 7.28.3
|
'@babel/traverse': 7.28.4
|
||||||
'@babel/types': 7.28.2
|
'@babel/types': 7.28.4
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@babel/helper-module-transforms@7.28.3(@babel/core@7.28.3)':
|
'@babel/helper-module-transforms@7.28.3(@babel/core@7.28.4)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.28.3
|
'@babel/core': 7.28.4
|
||||||
'@babel/helper-module-imports': 7.27.1
|
'@babel/helper-module-imports': 7.27.1
|
||||||
'@babel/helper-validator-identifier': 7.27.1
|
'@babel/helper-validator-identifier': 7.27.1
|
||||||
'@babel/traverse': 7.28.3
|
'@babel/traverse': 7.28.4
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -706,44 +700,44 @@ snapshots:
|
|||||||
|
|
||||||
'@babel/helper-validator-option@7.27.1': {}
|
'@babel/helper-validator-option@7.27.1': {}
|
||||||
|
|
||||||
'@babel/helpers@7.28.3':
|
'@babel/helpers@7.28.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/template': 7.27.2
|
'@babel/template': 7.27.2
|
||||||
'@babel/types': 7.28.2
|
'@babel/types': 7.28.4
|
||||||
|
|
||||||
'@babel/parser@7.28.3':
|
'@babel/parser@7.28.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/types': 7.28.2
|
'@babel/types': 7.28.4
|
||||||
|
|
||||||
'@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.3)':
|
'@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.4)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.28.3
|
'@babel/core': 7.28.4
|
||||||
'@babel/helper-plugin-utils': 7.27.1
|
'@babel/helper-plugin-utils': 7.27.1
|
||||||
|
|
||||||
'@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.3)':
|
'@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.4)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.28.3
|
'@babel/core': 7.28.4
|
||||||
'@babel/helper-plugin-utils': 7.27.1
|
'@babel/helper-plugin-utils': 7.27.1
|
||||||
|
|
||||||
'@babel/template@7.27.2':
|
'@babel/template@7.27.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/code-frame': 7.27.1
|
'@babel/code-frame': 7.27.1
|
||||||
'@babel/parser': 7.28.3
|
'@babel/parser': 7.28.4
|
||||||
'@babel/types': 7.28.2
|
'@babel/types': 7.28.4
|
||||||
|
|
||||||
'@babel/traverse@7.28.3':
|
'@babel/traverse@7.28.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/code-frame': 7.27.1
|
'@babel/code-frame': 7.27.1
|
||||||
'@babel/generator': 7.28.3
|
'@babel/generator': 7.28.3
|
||||||
'@babel/helper-globals': 7.28.0
|
'@babel/helper-globals': 7.28.0
|
||||||
'@babel/parser': 7.28.3
|
'@babel/parser': 7.28.4
|
||||||
'@babel/template': 7.27.2
|
'@babel/template': 7.27.2
|
||||||
'@babel/types': 7.28.2
|
'@babel/types': 7.28.4
|
||||||
debug: 4.4.1
|
debug: 4.4.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@babel/types@7.28.2':
|
'@babel/types@7.28.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/helper-string-parser': 7.27.1
|
'@babel/helper-string-parser': 7.27.1
|
||||||
'@babel/helper-validator-identifier': 7.27.1
|
'@babel/helper-validator-identifier': 7.27.1
|
||||||
@@ -831,6 +825,11 @@ snapshots:
|
|||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
'@jridgewell/trace-mapping': 0.3.30
|
'@jridgewell/trace-mapping': 0.3.30
|
||||||
|
|
||||||
|
'@jridgewell/remapping@2.3.5':
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/gen-mapping': 0.3.13
|
||||||
|
'@jridgewell/trace-mapping': 0.3.30
|
||||||
|
|
||||||
'@jridgewell/resolve-uri@3.1.2': {}
|
'@jridgewell/resolve-uri@3.1.2': {}
|
||||||
|
|
||||||
'@jridgewell/sourcemap-codec@1.5.5': {}
|
'@jridgewell/sourcemap-codec@1.5.5': {}
|
||||||
@@ -909,24 +908,24 @@ snapshots:
|
|||||||
|
|
||||||
'@types/babel__core@7.20.5':
|
'@types/babel__core@7.20.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/parser': 7.28.3
|
'@babel/parser': 7.28.4
|
||||||
'@babel/types': 7.28.2
|
'@babel/types': 7.28.4
|
||||||
'@types/babel__generator': 7.27.0
|
'@types/babel__generator': 7.27.0
|
||||||
'@types/babel__template': 7.4.4
|
'@types/babel__template': 7.4.4
|
||||||
'@types/babel__traverse': 7.28.0
|
'@types/babel__traverse': 7.28.0
|
||||||
|
|
||||||
'@types/babel__generator@7.27.0':
|
'@types/babel__generator@7.27.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/types': 7.28.2
|
'@babel/types': 7.28.4
|
||||||
|
|
||||||
'@types/babel__template@7.4.4':
|
'@types/babel__template@7.4.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/parser': 7.28.3
|
'@babel/parser': 7.28.4
|
||||||
'@babel/types': 7.28.2
|
'@babel/types': 7.28.4
|
||||||
|
|
||||||
'@types/babel__traverse@7.28.0':
|
'@types/babel__traverse@7.28.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/types': 7.28.2
|
'@babel/types': 7.28.4
|
||||||
|
|
||||||
'@types/estree@1.0.8': {}
|
'@types/estree@1.0.8': {}
|
||||||
|
|
||||||
@@ -938,15 +937,15 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
csstype: 3.1.3
|
csstype: 3.1.3
|
||||||
|
|
||||||
'@vitejs/plugin-react@4.7.0(vite@7.1.4)':
|
'@vitejs/plugin-react@4.7.0(vite@7.1.11)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.28.3
|
'@babel/core': 7.28.4
|
||||||
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.3)
|
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4)
|
||||||
'@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.3)
|
'@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.4)
|
||||||
'@rolldown/pluginutils': 1.0.0-beta.27
|
'@rolldown/pluginutils': 1.0.0-beta.27
|
||||||
'@types/babel__core': 7.20.5
|
'@types/babel__core': 7.20.5
|
||||||
react-refresh: 0.17.0
|
react-refresh: 0.17.0
|
||||||
vite: 7.1.4
|
vite: 7.1.11
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -1095,7 +1094,7 @@ snapshots:
|
|||||||
|
|
||||||
source-map-js@1.2.1: {}
|
source-map-js@1.2.1: {}
|
||||||
|
|
||||||
tinyglobby@0.2.14:
|
tinyglobby@0.2.15:
|
||||||
dependencies:
|
dependencies:
|
||||||
fdir: 6.5.0(picomatch@4.0.3)
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
picomatch: 4.0.3
|
picomatch: 4.0.3
|
||||||
@@ -1106,14 +1105,14 @@ snapshots:
|
|||||||
escalade: 3.2.0
|
escalade: 3.2.0
|
||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
|
|
||||||
vite@7.1.4:
|
vite@7.1.11:
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.25.9
|
esbuild: 0.25.9
|
||||||
fdir: 6.5.0(picomatch@4.0.3)
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
picomatch: 4.0.3
|
picomatch: 4.0.3
|
||||||
postcss: 8.5.6
|
postcss: 8.5.6
|
||||||
rollup: 4.50.0
|
rollup: 4.50.0
|
||||||
tinyglobby: 0.2.14
|
tinyglobby: 0.2.15
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,6 @@
|
|||||||
"svelte": "^5.0.0",
|
"svelte": "^5.0.0",
|
||||||
"svelte-check": "^4.0.0",
|
"svelte-check": "^4.0.0",
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
"vite": "^7.0.4"
|
"vite": "^7.0.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
52
examples/demos/sveltekit-demo/pnpm-lock.yaml
generated
52
examples/demos/sveltekit-demo/pnpm-lock.yaml
generated
@@ -17,13 +17,13 @@ importers:
|
|||||||
devDependencies:
|
devDependencies:
|
||||||
'@sveltejs/adapter-auto':
|
'@sveltejs/adapter-auto':
|
||||||
specifier: ^6.0.0
|
specifier: ^6.0.0
|
||||||
version: 6.1.0(@sveltejs/kit@2.37.0(@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.6)(vite@7.1.4))(svelte@5.38.6)(vite@7.1.4))
|
version: 6.1.0(@sveltejs/kit@2.37.0(@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.6)(vite@7.1.11))(svelte@5.38.6)(vite@7.1.11))
|
||||||
'@sveltejs/kit':
|
'@sveltejs/kit':
|
||||||
specifier: ^2.22.0
|
specifier: ^2.22.0
|
||||||
version: 2.37.0(@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.6)(vite@7.1.4))(svelte@5.38.6)(vite@7.1.4)
|
version: 2.37.0(@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.6)(vite@7.1.11))(svelte@5.38.6)(vite@7.1.11)
|
||||||
'@sveltejs/vite-plugin-svelte':
|
'@sveltejs/vite-plugin-svelte':
|
||||||
specifier: ^6.0.0
|
specifier: ^6.0.0
|
||||||
version: 6.1.4(svelte@5.38.6)(vite@7.1.4)
|
version: 6.1.4(svelte@5.38.6)(vite@7.1.11)
|
||||||
globals:
|
globals:
|
||||||
specifier: ^16.0.0
|
specifier: ^16.0.0
|
||||||
version: 16.3.0
|
version: 16.3.0
|
||||||
@@ -43,8 +43,8 @@ importers:
|
|||||||
specifier: ^5.0.0
|
specifier: ^5.0.0
|
||||||
version: 5.9.2
|
version: 5.9.2
|
||||||
vite:
|
vite:
|
||||||
specifier: ^7.0.4
|
specifier: ^7.0.8
|
||||||
version: 7.1.4
|
version: 7.1.11
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -535,8 +535,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-ltBPlkvqk3bgCK7/N323atUpP3O3Y+DrGV4dcULrsSn4fZaaNnOmdplNznwfdWclAgvSr5rxjtzn/zJhRm6TKg==}
|
resolution: {integrity: sha512-ltBPlkvqk3bgCK7/N323atUpP3O3Y+DrGV4dcULrsSn4fZaaNnOmdplNznwfdWclAgvSr5rxjtzn/zJhRm6TKg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
tinyglobby@0.2.14:
|
tinyglobby@0.2.15:
|
||||||
resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
|
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
totalist@3.0.1:
|
totalist@3.0.1:
|
||||||
@@ -548,8 +548,8 @@ packages:
|
|||||||
engines: {node: '>=14.17'}
|
engines: {node: '>=14.17'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
vite@7.1.4:
|
vite@7.1.11:
|
||||||
resolution: {integrity: sha512-X5QFK4SGynAeeIt+A7ZWnApdUyHYm+pzv/8/A57LqSGcI88U6R6ipOs3uCesdc6yl7nl+zNO0t8LmqAdXcQihw==}
|
resolution: {integrity: sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -771,15 +771,15 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
acorn: 8.15.0
|
acorn: 8.15.0
|
||||||
|
|
||||||
'@sveltejs/adapter-auto@6.1.0(@sveltejs/kit@2.37.0(@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.6)(vite@7.1.4))(svelte@5.38.6)(vite@7.1.4))':
|
'@sveltejs/adapter-auto@6.1.0(@sveltejs/kit@2.37.0(@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.6)(vite@7.1.11))(svelte@5.38.6)(vite@7.1.11))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/kit': 2.37.0(@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.6)(vite@7.1.4))(svelte@5.38.6)(vite@7.1.4)
|
'@sveltejs/kit': 2.37.0(@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.6)(vite@7.1.11))(svelte@5.38.6)(vite@7.1.11)
|
||||||
|
|
||||||
'@sveltejs/kit@2.37.0(@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.6)(vite@7.1.4))(svelte@5.38.6)(vite@7.1.4)':
|
'@sveltejs/kit@2.37.0(@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.6)(vite@7.1.11))(svelte@5.38.6)(vite@7.1.11)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@standard-schema/spec': 1.0.0
|
'@standard-schema/spec': 1.0.0
|
||||||
'@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0)
|
'@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0)
|
||||||
'@sveltejs/vite-plugin-svelte': 6.1.4(svelte@5.38.6)(vite@7.1.4)
|
'@sveltejs/vite-plugin-svelte': 6.1.4(svelte@5.38.6)(vite@7.1.11)
|
||||||
'@types/cookie': 0.6.0
|
'@types/cookie': 0.6.0
|
||||||
acorn: 8.15.0
|
acorn: 8.15.0
|
||||||
cookie: 0.6.0
|
cookie: 0.6.0
|
||||||
@@ -792,26 +792,26 @@ snapshots:
|
|||||||
set-cookie-parser: 2.7.1
|
set-cookie-parser: 2.7.1
|
||||||
sirv: 3.0.2
|
sirv: 3.0.2
|
||||||
svelte: 5.38.6
|
svelte: 5.38.6
|
||||||
vite: 7.1.4
|
vite: 7.1.11
|
||||||
|
|
||||||
'@sveltejs/vite-plugin-svelte-inspector@5.0.1(@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.6)(vite@7.1.4))(svelte@5.38.6)(vite@7.1.4)':
|
'@sveltejs/vite-plugin-svelte-inspector@5.0.1(@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.6)(vite@7.1.11))(svelte@5.38.6)(vite@7.1.11)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/vite-plugin-svelte': 6.1.4(svelte@5.38.6)(vite@7.1.4)
|
'@sveltejs/vite-plugin-svelte': 6.1.4(svelte@5.38.6)(vite@7.1.11)
|
||||||
debug: 4.4.1
|
debug: 4.4.1
|
||||||
svelte: 5.38.6
|
svelte: 5.38.6
|
||||||
vite: 7.1.4
|
vite: 7.1.11
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.6)(vite@7.1.4)':
|
'@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.6)(vite@7.1.11)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/vite-plugin-svelte-inspector': 5.0.1(@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.6)(vite@7.1.4))(svelte@5.38.6)(vite@7.1.4)
|
'@sveltejs/vite-plugin-svelte-inspector': 5.0.1(@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.6)(vite@7.1.11))(svelte@5.38.6)(vite@7.1.11)
|
||||||
debug: 4.4.1
|
debug: 4.4.1
|
||||||
deepmerge: 4.3.1
|
deepmerge: 4.3.1
|
||||||
magic-string: 0.30.18
|
magic-string: 0.30.18
|
||||||
svelte: 5.38.6
|
svelte: 5.38.6
|
||||||
vite: 7.1.4
|
vite: 7.1.11
|
||||||
vitefu: 1.1.1(vite@7.1.4)
|
vitefu: 1.1.1(vite@7.1.11)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -994,7 +994,7 @@ snapshots:
|
|||||||
magic-string: 0.30.18
|
magic-string: 0.30.18
|
||||||
zimmerframe: 1.1.2
|
zimmerframe: 1.1.2
|
||||||
|
|
||||||
tinyglobby@0.2.14:
|
tinyglobby@0.2.15:
|
||||||
dependencies:
|
dependencies:
|
||||||
fdir: 6.5.0(picomatch@4.0.3)
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
picomatch: 4.0.3
|
picomatch: 4.0.3
|
||||||
@@ -1003,19 +1003,19 @@ snapshots:
|
|||||||
|
|
||||||
typescript@5.9.2: {}
|
typescript@5.9.2: {}
|
||||||
|
|
||||||
vite@7.1.4:
|
vite@7.1.11:
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.25.9
|
esbuild: 0.25.9
|
||||||
fdir: 6.5.0(picomatch@4.0.3)
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
picomatch: 4.0.3
|
picomatch: 4.0.3
|
||||||
postcss: 8.5.6
|
postcss: 8.5.6
|
||||||
rollup: 4.50.0
|
rollup: 4.50.0
|
||||||
tinyglobby: 0.2.14
|
tinyglobby: 0.2.15
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
|
|
||||||
vitefu@1.1.1(vite@7.1.4):
|
vitefu@1.1.1(vite@7.1.11):
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 7.1.4
|
vite: 7.1.11
|
||||||
|
|
||||||
zimmerframe@1.1.2: {}
|
zimmerframe@1.1.2: {}
|
||||||
|
|||||||
955
examples/demos/vue-demo/pnpm-lock.yaml
generated
955
examples/demos/vue-demo/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
1836
examples/guides/react-apollo/pnpm-lock.yaml
generated
1836
examples/guides/react-apollo/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
1150
examples/guides/react-query/pnpm-lock.yaml
generated
1150
examples/guides/react-query/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
926
examples/guides/react-urql/pnpm-lock.yaml
generated
926
examples/guides/react-urql/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -23,6 +23,6 @@
|
|||||||
"eslint-plugin-react-hooks": "^5.2.0",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.20",
|
"eslint-plugin-react-refresh": "^0.4.20",
|
||||||
"globals": "^16.3.0",
|
"globals": "^16.3.0",
|
||||||
"vite": "^7.1.2"
|
"vite": "^7.1.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
examples/quickstarts/react/pnpm-lock.yaml
generated
16
examples/quickstarts/react/pnpm-lock.yaml
generated
@@ -29,7 +29,7 @@ importers:
|
|||||||
version: 19.1.9(@types/react@19.1.12)
|
version: 19.1.9(@types/react@19.1.12)
|
||||||
'@vitejs/plugin-react':
|
'@vitejs/plugin-react':
|
||||||
specifier: ^5.0.0
|
specifier: ^5.0.0
|
||||||
version: 5.0.2(vite@7.1.5)
|
version: 5.0.2(vite@7.1.11)
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^9.33.0
|
specifier: ^9.33.0
|
||||||
version: 9.35.0
|
version: 9.35.0
|
||||||
@@ -43,8 +43,8 @@ importers:
|
|||||||
specifier: ^16.3.0
|
specifier: ^16.3.0
|
||||||
version: 16.3.0
|
version: 16.3.0
|
||||||
vite:
|
vite:
|
||||||
specifier: ^7.1.2
|
specifier: ^7.1.11
|
||||||
version: 7.1.5
|
version: 7.1.11
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -890,8 +890,8 @@ packages:
|
|||||||
uri-js@4.4.1:
|
uri-js@4.4.1:
|
||||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||||
|
|
||||||
vite@7.1.5:
|
vite@7.1.11:
|
||||||
resolution: {integrity: sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==}
|
resolution: {integrity: sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -1310,7 +1310,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
csstype: 3.1.3
|
csstype: 3.1.3
|
||||||
|
|
||||||
'@vitejs/plugin-react@5.0.2(vite@7.1.5)':
|
'@vitejs/plugin-react@5.0.2(vite@7.1.11)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.28.4
|
'@babel/core': 7.28.4
|
||||||
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4)
|
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4)
|
||||||
@@ -1318,7 +1318,7 @@ snapshots:
|
|||||||
'@rolldown/pluginutils': 1.0.0-beta.34
|
'@rolldown/pluginutils': 1.0.0-beta.34
|
||||||
'@types/babel__core': 7.20.5
|
'@types/babel__core': 7.20.5
|
||||||
react-refresh: 0.17.0
|
react-refresh: 0.17.0
|
||||||
vite: 7.1.5
|
vite: 7.1.11
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -1717,7 +1717,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
punycode: 2.3.1
|
punycode: 2.3.1
|
||||||
|
|
||||||
vite@7.1.5:
|
vite@7.1.11:
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.25.9
|
esbuild: 0.25.9
|
||||||
fdir: 6.5.0(picomatch@4.0.3)
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
|
|||||||
@@ -14,6 +14,6 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/vite-plugin-svelte": "^6.1.1",
|
"@sveltejs/vite-plugin-svelte": "^6.1.1",
|
||||||
"svelte": "^5.38.1",
|
"svelte": "^5.38.1",
|
||||||
"vite": "^7.1.2"
|
"vite": "^7.1.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
30
examples/quickstarts/svelte/pnpm-lock.yaml
generated
30
examples/quickstarts/svelte/pnpm-lock.yaml
generated
@@ -14,13 +14,13 @@ importers:
|
|||||||
devDependencies:
|
devDependencies:
|
||||||
'@sveltejs/vite-plugin-svelte':
|
'@sveltejs/vite-plugin-svelte':
|
||||||
specifier: ^6.1.1
|
specifier: ^6.1.1
|
||||||
version: 6.1.4(svelte@5.38.7)(vite@7.1.5)
|
version: 6.1.4(svelte@5.38.7)(vite@7.1.11)
|
||||||
svelte:
|
svelte:
|
||||||
specifier: ^5.38.1
|
specifier: ^5.38.1
|
||||||
version: 5.38.7
|
version: 5.38.7
|
||||||
vite:
|
vite:
|
||||||
specifier: ^7.1.2
|
specifier: ^7.1.11
|
||||||
version: 7.1.5
|
version: 7.1.11
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -424,8 +424,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
|
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
vite@7.1.5:
|
vite@7.1.11:
|
||||||
resolution: {integrity: sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==}
|
resolution: {integrity: sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -641,24 +641,24 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
acorn: 8.15.0
|
acorn: 8.15.0
|
||||||
|
|
||||||
'@sveltejs/vite-plugin-svelte-inspector@5.0.1(@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.7)(vite@7.1.5))(svelte@5.38.7)(vite@7.1.5)':
|
'@sveltejs/vite-plugin-svelte-inspector@5.0.1(@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.7)(vite@7.1.11))(svelte@5.38.7)(vite@7.1.11)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/vite-plugin-svelte': 6.1.4(svelte@5.38.7)(vite@7.1.5)
|
'@sveltejs/vite-plugin-svelte': 6.1.4(svelte@5.38.7)(vite@7.1.11)
|
||||||
debug: 4.4.1
|
debug: 4.4.1
|
||||||
svelte: 5.38.7
|
svelte: 5.38.7
|
||||||
vite: 7.1.5
|
vite: 7.1.11
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.7)(vite@7.1.5)':
|
'@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.7)(vite@7.1.11)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/vite-plugin-svelte-inspector': 5.0.1(@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.7)(vite@7.1.5))(svelte@5.38.7)(vite@7.1.5)
|
'@sveltejs/vite-plugin-svelte-inspector': 5.0.1(@sveltejs/vite-plugin-svelte@6.1.4(svelte@5.38.7)(vite@7.1.11))(svelte@5.38.7)(vite@7.1.11)
|
||||||
debug: 4.4.1
|
debug: 4.4.1
|
||||||
deepmerge: 4.3.1
|
deepmerge: 4.3.1
|
||||||
magic-string: 0.30.18
|
magic-string: 0.30.18
|
||||||
svelte: 5.38.7
|
svelte: 5.38.7
|
||||||
vite: 7.1.5
|
vite: 7.1.11
|
||||||
vitefu: 1.1.1(vite@7.1.5)
|
vitefu: 1.1.1(vite@7.1.11)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -795,7 +795,7 @@ snapshots:
|
|||||||
fdir: 6.5.0(picomatch@4.0.3)
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
picomatch: 4.0.3
|
picomatch: 4.0.3
|
||||||
|
|
||||||
vite@7.1.5:
|
vite@7.1.11:
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.25.9
|
esbuild: 0.25.9
|
||||||
fdir: 6.5.0(picomatch@4.0.3)
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
@@ -806,8 +806,8 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
|
|
||||||
vitefu@1.1.1(vite@7.1.5):
|
vitefu@1.1.1(vite@7.1.11):
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 7.1.5
|
vite: 7.1.11
|
||||||
|
|
||||||
zimmerframe@1.1.2: {}
|
zimmerframe@1.1.2: {}
|
||||||
|
|||||||
@@ -14,6 +14,6 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^6.0.1",
|
"@vitejs/plugin-vue": "^6.0.1",
|
||||||
"vite": "^7.1.2"
|
"vite": "^7.1.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
examples/quickstarts/vue/pnpm-lock.yaml
generated
16
examples/quickstarts/vue/pnpm-lock.yaml
generated
@@ -17,10 +17,10 @@ importers:
|
|||||||
devDependencies:
|
devDependencies:
|
||||||
'@vitejs/plugin-vue':
|
'@vitejs/plugin-vue':
|
||||||
specifier: ^6.0.1
|
specifier: ^6.0.1
|
||||||
version: 6.0.1(vite@7.1.5)(vue@3.5.21)
|
version: 6.0.1(vite@7.1.11)(vue@3.5.21)
|
||||||
vite:
|
vite:
|
||||||
specifier: ^7.1.2
|
specifier: ^7.1.11
|
||||||
version: 7.1.5
|
version: 7.1.11
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -408,8 +408,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
|
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
vite@7.1.5:
|
vite@7.1.11:
|
||||||
resolution: {integrity: sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==}
|
resolution: {integrity: sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -618,10 +618,10 @@ snapshots:
|
|||||||
|
|
||||||
'@types/estree@1.0.8': {}
|
'@types/estree@1.0.8': {}
|
||||||
|
|
||||||
'@vitejs/plugin-vue@6.0.1(vite@7.1.5)(vue@3.5.21)':
|
'@vitejs/plugin-vue@6.0.1(vite@7.1.11)(vue@3.5.21)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@rolldown/pluginutils': 1.0.0-beta.29
|
'@rolldown/pluginutils': 1.0.0-beta.29
|
||||||
vite: 7.1.5
|
vite: 7.1.11
|
||||||
vue: 3.5.21
|
vue: 3.5.21
|
||||||
|
|
||||||
'@vue/compiler-core@3.5.21':
|
'@vue/compiler-core@3.5.21':
|
||||||
@@ -770,7 +770,7 @@ snapshots:
|
|||||||
fdir: 6.5.0(picomatch@4.0.3)
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
picomatch: 4.0.3
|
picomatch: 4.0.3
|
||||||
|
|
||||||
vite@7.1.5:
|
vite@7.1.11:
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.25.9
|
esbuild: 0.25.9
|
||||||
fdir: 6.5.0(picomatch@4.0.3)
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ rating = 'g'
|
|||||||
|
|
||||||
[auth.session]
|
[auth.session]
|
||||||
[auth.session.accessToken]
|
[auth.session.accessToken]
|
||||||
expiresIn = 900
|
expiresIn = 65
|
||||||
|
|
||||||
[auth.session.refreshToken]
|
[auth.session.refreshToken]
|
||||||
expiresIn = 2592000
|
expiresIn = 2592000
|
||||||
|
|||||||
@@ -25,6 +25,6 @@
|
|||||||
"@vitejs/plugin-react": "^5.0.0",
|
"@vitejs/plugin-react": "^5.0.0",
|
||||||
"globals": "^16.3.0",
|
"globals": "^16.3.0",
|
||||||
"typescript": "~5.8.3",
|
"typescript": "~5.8.3",
|
||||||
"vite": "^7.1.2"
|
"vite": "^7.1.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ importers:
|
|||||||
version: 19.1.9(@types/react@19.1.12)
|
version: 19.1.9(@types/react@19.1.12)
|
||||||
'@vitejs/plugin-react':
|
'@vitejs/plugin-react':
|
||||||
specifier: ^5.0.0
|
specifier: ^5.0.0
|
||||||
version: 5.0.2(vite@7.1.5)
|
version: 5.0.2(vite@7.1.11)
|
||||||
globals:
|
globals:
|
||||||
specifier: ^16.3.0
|
specifier: ^16.3.0
|
||||||
version: 16.4.0
|
version: 16.4.0
|
||||||
@@ -37,8 +37,8 @@ importers:
|
|||||||
specifier: ~5.8.3
|
specifier: ~5.8.3
|
||||||
version: 5.8.3
|
version: 5.8.3
|
||||||
vite:
|
vite:
|
||||||
specifier: ^7.1.2
|
specifier: ^7.1.11
|
||||||
version: 7.1.5
|
version: 7.1.11
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -597,8 +597,8 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
browserslist: '>= 4.21.0'
|
browserslist: '>= 4.21.0'
|
||||||
|
|
||||||
vite@7.1.5:
|
vite@7.1.11:
|
||||||
resolution: {integrity: sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==}
|
resolution: {integrity: sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -947,7 +947,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
csstype: 3.1.3
|
csstype: 3.1.3
|
||||||
|
|
||||||
'@vitejs/plugin-react@5.0.2(vite@7.1.5)':
|
'@vitejs/plugin-react@5.0.2(vite@7.1.11)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.28.4
|
'@babel/core': 7.28.4
|
||||||
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4)
|
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4)
|
||||||
@@ -955,7 +955,7 @@ snapshots:
|
|||||||
'@rolldown/pluginutils': 1.0.0-beta.34
|
'@rolldown/pluginutils': 1.0.0-beta.34
|
||||||
'@types/babel__core': 7.20.5
|
'@types/babel__core': 7.20.5
|
||||||
react-refresh: 0.17.0
|
react-refresh: 0.17.0
|
||||||
vite: 7.1.5
|
vite: 7.1.11
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -1119,7 +1119,7 @@ snapshots:
|
|||||||
escalade: 3.2.0
|
escalade: 3.2.0
|
||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
|
|
||||||
vite@7.1.5:
|
vite@7.1.11:
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.25.9
|
esbuild: 0.25.9
|
||||||
fdir: 6.5.0(picomatch@4.0.3)
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
|
|||||||
@@ -26,6 +26,6 @@
|
|||||||
"svelte": "^5.0.0",
|
"svelte": "^5.0.0",
|
||||||
"svelte-check": "^4.0.0",
|
"svelte-check": "^4.0.0",
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
"vite": "^7.0.4"
|
"vite": "^7.0.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ importers:
|
|||||||
devDependencies:
|
devDependencies:
|
||||||
'@sveltejs/adapter-auto':
|
'@sveltejs/adapter-auto':
|
||||||
specifier: ^6.0.0
|
specifier: ^6.0.0
|
||||||
version: 6.1.0(@sveltejs/kit@2.41.0(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.38.10)(vite@7.1.5))(svelte@5.38.10)(vite@7.1.5))
|
version: 6.1.0(@sveltejs/kit@2.41.0(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.38.10)(vite@7.1.11))(svelte@5.38.10)(vite@7.1.11))
|
||||||
'@sveltejs/kit':
|
'@sveltejs/kit':
|
||||||
specifier: ^2.22.0
|
specifier: ^2.22.0
|
||||||
version: 2.41.0(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.38.10)(vite@7.1.5))(svelte@5.38.10)(vite@7.1.5)
|
version: 2.41.0(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.38.10)(vite@7.1.11))(svelte@5.38.10)(vite@7.1.11)
|
||||||
'@sveltejs/vite-plugin-svelte':
|
'@sveltejs/vite-plugin-svelte':
|
||||||
specifier: ^6.0.0
|
specifier: ^6.0.0
|
||||||
version: 6.2.0(svelte@5.38.10)(vite@7.1.5)
|
version: 6.2.0(svelte@5.38.10)(vite@7.1.11)
|
||||||
svelte:
|
svelte:
|
||||||
specifier: ^5.0.0
|
specifier: ^5.0.0
|
||||||
version: 5.38.10
|
version: 5.38.10
|
||||||
@@ -31,8 +31,8 @@ importers:
|
|||||||
specifier: ^5.0.0
|
specifier: ^5.0.0
|
||||||
version: 5.9.2
|
version: 5.9.2
|
||||||
vite:
|
vite:
|
||||||
specifier: ^7.0.4
|
specifier: ^7.0.8
|
||||||
version: 7.1.5
|
version: 7.1.11
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -518,8 +518,8 @@ packages:
|
|||||||
engines: {node: '>=14.17'}
|
engines: {node: '>=14.17'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
vite@7.1.5:
|
vite@7.1.11:
|
||||||
resolution: {integrity: sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==}
|
resolution: {integrity: sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -739,15 +739,15 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
acorn: 8.15.0
|
acorn: 8.15.0
|
||||||
|
|
||||||
'@sveltejs/adapter-auto@6.1.0(@sveltejs/kit@2.41.0(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.38.10)(vite@7.1.5))(svelte@5.38.10)(vite@7.1.5))':
|
'@sveltejs/adapter-auto@6.1.0(@sveltejs/kit@2.41.0(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.38.10)(vite@7.1.11))(svelte@5.38.10)(vite@7.1.11))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/kit': 2.41.0(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.38.10)(vite@7.1.5))(svelte@5.38.10)(vite@7.1.5)
|
'@sveltejs/kit': 2.41.0(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.38.10)(vite@7.1.11))(svelte@5.38.10)(vite@7.1.11)
|
||||||
|
|
||||||
'@sveltejs/kit@2.41.0(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.38.10)(vite@7.1.5))(svelte@5.38.10)(vite@7.1.5)':
|
'@sveltejs/kit@2.41.0(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.38.10)(vite@7.1.11))(svelte@5.38.10)(vite@7.1.11)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@standard-schema/spec': 1.0.0
|
'@standard-schema/spec': 1.0.0
|
||||||
'@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0)
|
'@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0)
|
||||||
'@sveltejs/vite-plugin-svelte': 6.2.0(svelte@5.38.10)(vite@7.1.5)
|
'@sveltejs/vite-plugin-svelte': 6.2.0(svelte@5.38.10)(vite@7.1.11)
|
||||||
'@types/cookie': 0.6.0
|
'@types/cookie': 0.6.0
|
||||||
acorn: 8.15.0
|
acorn: 8.15.0
|
||||||
cookie: 0.6.0
|
cookie: 0.6.0
|
||||||
@@ -760,26 +760,26 @@ snapshots:
|
|||||||
set-cookie-parser: 2.7.1
|
set-cookie-parser: 2.7.1
|
||||||
sirv: 3.0.2
|
sirv: 3.0.2
|
||||||
svelte: 5.38.10
|
svelte: 5.38.10
|
||||||
vite: 7.1.5
|
vite: 7.1.11
|
||||||
|
|
||||||
'@sveltejs/vite-plugin-svelte-inspector@5.0.1(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.38.10)(vite@7.1.5))(svelte@5.38.10)(vite@7.1.5)':
|
'@sveltejs/vite-plugin-svelte-inspector@5.0.1(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.38.10)(vite@7.1.11))(svelte@5.38.10)(vite@7.1.11)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/vite-plugin-svelte': 6.2.0(svelte@5.38.10)(vite@7.1.5)
|
'@sveltejs/vite-plugin-svelte': 6.2.0(svelte@5.38.10)(vite@7.1.11)
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
svelte: 5.38.10
|
svelte: 5.38.10
|
||||||
vite: 7.1.5
|
vite: 7.1.11
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.38.10)(vite@7.1.5)':
|
'@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.38.10)(vite@7.1.11)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/vite-plugin-svelte-inspector': 5.0.1(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.38.10)(vite@7.1.5))(svelte@5.38.10)(vite@7.1.5)
|
'@sveltejs/vite-plugin-svelte-inspector': 5.0.1(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.38.10)(vite@7.1.11))(svelte@5.38.10)(vite@7.1.11)
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
deepmerge: 4.3.1
|
deepmerge: 4.3.1
|
||||||
magic-string: 0.30.19
|
magic-string: 0.30.19
|
||||||
svelte: 5.38.10
|
svelte: 5.38.10
|
||||||
vite: 7.1.5
|
vite: 7.1.11
|
||||||
vitefu: 1.1.1(vite@7.1.5)
|
vitefu: 1.1.1(vite@7.1.11)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -962,7 +962,7 @@ snapshots:
|
|||||||
|
|
||||||
typescript@5.9.2: {}
|
typescript@5.9.2: {}
|
||||||
|
|
||||||
vite@7.1.5:
|
vite@7.1.11:
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.25.9
|
esbuild: 0.25.9
|
||||||
fdir: 6.5.0(picomatch@4.0.3)
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
@@ -973,8 +973,8 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
|
|
||||||
vitefu@1.1.1(vite@7.1.5):
|
vitefu@1.1.1(vite@7.1.11):
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 7.1.5
|
vite: 7.1.11
|
||||||
|
|
||||||
zimmerframe@1.1.4: {}
|
zimmerframe@1.1.4: {}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
"@vue/tsconfig": "^0.7.0",
|
"@vue/tsconfig": "^0.7.0",
|
||||||
"npm-run-all2": "^8.0.4",
|
"npm-run-all2": "^8.0.4",
|
||||||
"typescript": "~5.8.0",
|
"typescript": "~5.8.0",
|
||||||
"vite": "^7.0.6",
|
"vite": "^7.0.8",
|
||||||
"vite-plugin-vue-devtools": "^8.0.0",
|
"vite-plugin-vue-devtools": "^8.0.0",
|
||||||
"vue-tsc": "^3.0.4"
|
"vue-tsc": "^3.0.4"
|
||||||
}
|
}
|
||||||
|
|||||||
52
examples/tutorials/nhost-vue-tutorial/pnpm-lock.yaml
generated
52
examples/tutorials/nhost-vue-tutorial/pnpm-lock.yaml
generated
@@ -26,7 +26,7 @@ importers:
|
|||||||
version: 22.18.3
|
version: 22.18.3
|
||||||
'@vitejs/plugin-vue':
|
'@vitejs/plugin-vue':
|
||||||
specifier: ^6.0.1
|
specifier: ^6.0.1
|
||||||
version: 6.0.1(vite@7.1.5(@types/node@22.18.3))(vue@3.5.21(typescript@5.8.3))
|
version: 6.0.1(vite@7.1.11(@types/node@22.18.3))(vue@3.5.21(typescript@5.8.3))
|
||||||
'@vue/tsconfig':
|
'@vue/tsconfig':
|
||||||
specifier: ^0.7.0
|
specifier: ^0.7.0
|
||||||
version: 0.7.0(typescript@5.8.3)(vue@3.5.21(typescript@5.8.3))
|
version: 0.7.0(typescript@5.8.3)(vue@3.5.21(typescript@5.8.3))
|
||||||
@@ -37,11 +37,11 @@ importers:
|
|||||||
specifier: ~5.8.0
|
specifier: ~5.8.0
|
||||||
version: 5.8.3
|
version: 5.8.3
|
||||||
vite:
|
vite:
|
||||||
specifier: ^7.0.6
|
specifier: ^7.0.8
|
||||||
version: 7.1.5(@types/node@22.18.3)
|
version: 7.1.11(@types/node@22.18.3)
|
||||||
vite-plugin-vue-devtools:
|
vite-plugin-vue-devtools:
|
||||||
specifier: ^8.0.0
|
specifier: ^8.0.0
|
||||||
version: 8.0.2(vite@7.1.5(@types/node@22.18.3))(vue@3.5.21(typescript@5.8.3))
|
version: 8.0.2(vite@7.1.11(@types/node@22.18.3))(vue@3.5.21(typescript@5.8.3))
|
||||||
vue-tsc:
|
vue-tsc:
|
||||||
specifier: ^3.0.4
|
specifier: ^3.0.4
|
||||||
version: 3.0.7(typescript@5.8.3)
|
version: 3.0.7(typescript@5.8.3)
|
||||||
@@ -986,8 +986,8 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
vite: ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0
|
vite: ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0
|
||||||
|
|
||||||
vite@7.1.5:
|
vite@7.1.11:
|
||||||
resolution: {integrity: sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==}
|
resolution: {integrity: sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -1438,10 +1438,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 6.21.0
|
undici-types: 6.21.0
|
||||||
|
|
||||||
'@vitejs/plugin-vue@6.0.1(vite@7.1.5(@types/node@22.18.3))(vue@3.5.21(typescript@5.8.3))':
|
'@vitejs/plugin-vue@6.0.1(vite@7.1.11(@types/node@22.18.3))(vue@3.5.21(typescript@5.8.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@rolldown/pluginutils': 1.0.0-beta.29
|
'@rolldown/pluginutils': 1.0.0-beta.29
|
||||||
vite: 7.1.5(@types/node@22.18.3)
|
vite: 7.1.11(@types/node@22.18.3)
|
||||||
vue: 3.5.21(typescript@5.8.3)
|
vue: 3.5.21(typescript@5.8.3)
|
||||||
|
|
||||||
'@volar/language-core@2.4.23':
|
'@volar/language-core@2.4.23':
|
||||||
@@ -1522,14 +1522,14 @@ snapshots:
|
|||||||
|
|
||||||
'@vue/devtools-api@6.6.4': {}
|
'@vue/devtools-api@6.6.4': {}
|
||||||
|
|
||||||
'@vue/devtools-core@8.0.2(vite@7.1.5(@types/node@22.18.3))(vue@3.5.21(typescript@5.8.3))':
|
'@vue/devtools-core@8.0.2(vite@7.1.11(@types/node@22.18.3))(vue@3.5.21(typescript@5.8.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/devtools-kit': 8.0.2
|
'@vue/devtools-kit': 8.0.2
|
||||||
'@vue/devtools-shared': 8.0.2
|
'@vue/devtools-shared': 8.0.2
|
||||||
mitt: 3.0.1
|
mitt: 3.0.1
|
||||||
nanoid: 5.1.5
|
nanoid: 5.1.5
|
||||||
pathe: 2.0.3
|
pathe: 2.0.3
|
||||||
vite-hot-client: 2.1.0(vite@7.1.5(@types/node@22.18.3))
|
vite-hot-client: 2.1.0(vite@7.1.11(@types/node@22.18.3))
|
||||||
vue: 3.5.21(typescript@5.8.3)
|
vue: 3.5.21(typescript@5.8.3)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- vite
|
- vite
|
||||||
@@ -1920,17 +1920,17 @@ snapshots:
|
|||||||
escalade: 3.2.0
|
escalade: 3.2.0
|
||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
|
|
||||||
vite-dev-rpc@1.1.0(vite@7.1.5(@types/node@22.18.3)):
|
vite-dev-rpc@1.1.0(vite@7.1.11(@types/node@22.18.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
birpc: 2.5.0
|
birpc: 2.5.0
|
||||||
vite: 7.1.5(@types/node@22.18.3)
|
vite: 7.1.11(@types/node@22.18.3)
|
||||||
vite-hot-client: 2.1.0(vite@7.1.5(@types/node@22.18.3))
|
vite-hot-client: 2.1.0(vite@7.1.11(@types/node@22.18.3))
|
||||||
|
|
||||||
vite-hot-client@2.1.0(vite@7.1.5(@types/node@22.18.3)):
|
vite-hot-client@2.1.0(vite@7.1.11(@types/node@22.18.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
vite: 7.1.5(@types/node@22.18.3)
|
vite: 7.1.11(@types/node@22.18.3)
|
||||||
|
|
||||||
vite-plugin-inspect@11.3.3(vite@7.1.5(@types/node@22.18.3)):
|
vite-plugin-inspect@11.3.3(vite@7.1.11(@types/node@22.18.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
ansis: 4.1.0
|
ansis: 4.1.0
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
@@ -1940,27 +1940,27 @@ snapshots:
|
|||||||
perfect-debounce: 2.0.0
|
perfect-debounce: 2.0.0
|
||||||
sirv: 3.0.2
|
sirv: 3.0.2
|
||||||
unplugin-utils: 0.3.0
|
unplugin-utils: 0.3.0
|
||||||
vite: 7.1.5(@types/node@22.18.3)
|
vite: 7.1.11(@types/node@22.18.3)
|
||||||
vite-dev-rpc: 1.1.0(vite@7.1.5(@types/node@22.18.3))
|
vite-dev-rpc: 1.1.0(vite@7.1.11(@types/node@22.18.3))
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
vite-plugin-vue-devtools@8.0.2(vite@7.1.5(@types/node@22.18.3))(vue@3.5.21(typescript@5.8.3)):
|
vite-plugin-vue-devtools@8.0.2(vite@7.1.11(@types/node@22.18.3))(vue@3.5.21(typescript@5.8.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/devtools-core': 8.0.2(vite@7.1.5(@types/node@22.18.3))(vue@3.5.21(typescript@5.8.3))
|
'@vue/devtools-core': 8.0.2(vite@7.1.11(@types/node@22.18.3))(vue@3.5.21(typescript@5.8.3))
|
||||||
'@vue/devtools-kit': 8.0.2
|
'@vue/devtools-kit': 8.0.2
|
||||||
'@vue/devtools-shared': 8.0.2
|
'@vue/devtools-shared': 8.0.2
|
||||||
execa: 9.6.0
|
execa: 9.6.0
|
||||||
sirv: 3.0.2
|
sirv: 3.0.2
|
||||||
vite: 7.1.5(@types/node@22.18.3)
|
vite: 7.1.11(@types/node@22.18.3)
|
||||||
vite-plugin-inspect: 11.3.3(vite@7.1.5(@types/node@22.18.3))
|
vite-plugin-inspect: 11.3.3(vite@7.1.11(@types/node@22.18.3))
|
||||||
vite-plugin-vue-inspector: 5.3.2(vite@7.1.5(@types/node@22.18.3))
|
vite-plugin-vue-inspector: 5.3.2(vite@7.1.11(@types/node@22.18.3))
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@nuxt/kit'
|
- '@nuxt/kit'
|
||||||
- supports-color
|
- supports-color
|
||||||
- vue
|
- vue
|
||||||
|
|
||||||
vite-plugin-vue-inspector@5.3.2(vite@7.1.5(@types/node@22.18.3)):
|
vite-plugin-vue-inspector@5.3.2(vite@7.1.11(@types/node@22.18.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.28.4
|
'@babel/core': 7.28.4
|
||||||
'@babel/plugin-proposal-decorators': 7.28.0(@babel/core@7.28.4)
|
'@babel/plugin-proposal-decorators': 7.28.0(@babel/core@7.28.4)
|
||||||
@@ -1971,11 +1971,11 @@ snapshots:
|
|||||||
'@vue/compiler-dom': 3.5.21
|
'@vue/compiler-dom': 3.5.21
|
||||||
kolorist: 1.8.0
|
kolorist: 1.8.0
|
||||||
magic-string: 0.30.19
|
magic-string: 0.30.19
|
||||||
vite: 7.1.5(@types/node@22.18.3)
|
vite: 7.1.11(@types/node@22.18.3)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
vite@7.1.5(@types/node@22.18.3):
|
vite@7.1.11(@types/node@22.18.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.25.9
|
esbuild: 0.25.9
|
||||||
fdir: 6.5.0(picomatch@4.0.3)
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -29,7 +29,7 @@ require (
|
|||||||
github.com/jackc/pgx/v5 v5.7.2
|
github.com/jackc/pgx/v5 v5.7.2
|
||||||
github.com/lmittmann/tint v1.0.7
|
github.com/lmittmann/tint v1.0.7
|
||||||
github.com/mark3labs/mcp-go v0.41.1
|
github.com/mark3labs/mcp-go v0.41.1
|
||||||
github.com/nhost/be v0.0.0-20250929153845-6db3e5249d33
|
github.com/nhost/be v0.0.0-20251021065906-8abc7d8dfa48
|
||||||
github.com/oapi-codegen/gin-middleware v1.0.2
|
github.com/oapi-codegen/gin-middleware v1.0.2
|
||||||
github.com/oapi-codegen/runtime v1.1.1
|
github.com/oapi-codegen/runtime v1.1.1
|
||||||
github.com/pb33f/libopenapi v0.21.12
|
github.com/pb33f/libopenapi v0.21.12
|
||||||
|
|||||||
8
go.sum
8
go.sum
@@ -340,6 +340,14 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
|
|||||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||||
github.com/nhost/be v0.0.0-20250929153845-6db3e5249d33 h1:BNFN3Mw4zY6LEmVc7RXkHSVvHtovDSm7Oesb7IUt27o=
|
github.com/nhost/be v0.0.0-20250929153845-6db3e5249d33 h1:BNFN3Mw4zY6LEmVc7RXkHSVvHtovDSm7Oesb7IUt27o=
|
||||||
github.com/nhost/be v0.0.0-20250929153845-6db3e5249d33/go.mod h1:feVvqP3dft8hWbp9zNZExdGKbFEYv8aLYohfyAeINNQ=
|
github.com/nhost/be v0.0.0-20250929153845-6db3e5249d33/go.mod h1:feVvqP3dft8hWbp9zNZExdGKbFEYv8aLYohfyAeINNQ=
|
||||||
|
github.com/nhost/be v0.0.0-20251015125528-facecfb60cea h1:QQMCKMdkOkVN5PlZB/iiBSdQL6u84JIVppWf7hC5OoU=
|
||||||
|
github.com/nhost/be v0.0.0-20251015125528-facecfb60cea/go.mod h1:feVvqP3dft8hWbp9zNZExdGKbFEYv8aLYohfyAeINNQ=
|
||||||
|
github.com/nhost/be v0.0.0-20251020104454-acc8934d2c11 h1:5uPnBt2gjVkRpjUEJ8uS/q+FpvpTQJ+CN6zLCBYcfPA=
|
||||||
|
github.com/nhost/be v0.0.0-20251020104454-acc8934d2c11/go.mod h1:feVvqP3dft8hWbp9zNZExdGKbFEYv8aLYohfyAeINNQ=
|
||||||
|
github.com/nhost/be v0.0.0-20251020115144-85e0542ecec0 h1:MRWnaC1Aoir6JPr4v4C2TAVG5KBIgsOdWiDeII5HQYg=
|
||||||
|
github.com/nhost/be v0.0.0-20251020115144-85e0542ecec0/go.mod h1:feVvqP3dft8hWbp9zNZExdGKbFEYv8aLYohfyAeINNQ=
|
||||||
|
github.com/nhost/be v0.0.0-20251021065906-8abc7d8dfa48 h1:+Oh4Rbr1psWlBaQTakoBYFNB8jBioiXuimNMaNPLTHk=
|
||||||
|
github.com/nhost/be v0.0.0-20251021065906-8abc7d8dfa48/go.mod h1:feVvqP3dft8hWbp9zNZExdGKbFEYv8aLYohfyAeINNQ=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/oapi-codegen/gin-middleware v1.0.2 h1:/H99UzvHQAUxXK8pzdcGAZgjCVeXdFDAUUWaJT0k0eI=
|
github.com/oapi-codegen/gin-middleware v1.0.2 h1:/H99UzvHQAUxXK8pzdcGAZgjCVeXdFDAUUWaJT0k0eI=
|
||||||
github.com/oapi-codegen/gin-middleware v1.0.2/go.mod h1:2HJDQjH8jzK2/k/VKcWl+/T41H7ai2bKa6dN3AA2GpA=
|
github.com/oapi-codegen/gin-middleware v1.0.2/go.mod h1:2HJDQjH8jzK2/k/VKcWl+/T41H7ai2bKa6dN3AA2GpA=
|
||||||
|
|||||||
10
package.json
10
package.json
@@ -27,7 +27,7 @@
|
|||||||
"audit-ci": "^6.6.1",
|
"audit-ci": "^6.6.1",
|
||||||
"turbo": "2.3.3",
|
"turbo": "2.3.3",
|
||||||
"typescript": "5.8.3",
|
"typescript": "5.8.3",
|
||||||
"vite": "^5.4.20",
|
"vite": "^5.4.21",
|
||||||
"vite-tsconfig-paths": "^4.3.2",
|
"vite-tsconfig-paths": "^4.3.2",
|
||||||
"vitest": "^0.32.4"
|
"vitest": "^0.32.4"
|
||||||
},
|
},
|
||||||
@@ -60,7 +60,6 @@
|
|||||||
"zod@<=3.22.2": ">=3.22.3",
|
"zod@<=3.22.2": ">=3.22.3",
|
||||||
"@antfu/utils@<0.7.3": ">=0.7.3",
|
"@antfu/utils@<0.7.3": ">=0.7.3",
|
||||||
"next@>=0.9.9 <13.4.20-canary.13": ">=13.4.20-canary.13",
|
"next@>=0.9.9 <13.4.20-canary.13": ">=13.4.20-canary.13",
|
||||||
"vite@<=4.5.13": ">=4.5.14",
|
|
||||||
"yaml@>=2.0.0-5 <2.2.2": ">=2.2.2",
|
"yaml@>=2.0.0-5 <2.2.2": ">=2.2.2",
|
||||||
"pnpm@<7.33.4": ">=7.33.4",
|
"pnpm@<7.33.4": ">=7.33.4",
|
||||||
"graphql@>=16.3.0 <16.8.1": ">=16.8.1",
|
"graphql@>=16.3.0 <16.8.1": ">=16.8.1",
|
||||||
@@ -109,8 +108,11 @@
|
|||||||
"cookie@<0.7.0": ">=0.7.0",
|
"cookie@<0.7.0": ">=0.7.0",
|
||||||
"prismjs@<1.30.0": ">=1.30.0",
|
"prismjs@<1.30.0": ">=1.30.0",
|
||||||
"axios@<1.8.2": ">=1.8.2",
|
"axios@<1.8.2": ">=1.8.2",
|
||||||
"vite@>=5.0.0 <=5.4.18": ">=5.4.19",
|
"vite@<=4.5.13": ">=4.5.14",
|
||||||
"vite@>=6.2.0 <=6.2.6": ">=6.2.6",
|
"vite@>=5.0.0 <=5.4.20": ">=5.4.21",
|
||||||
|
"vite@>=6.0.0 <=6.4.0": ">=6.4.1",
|
||||||
|
"vite@>=7.0.0 <=7.0.7": "7.0.8",
|
||||||
|
"vite@>=7.1.0 <=7.1.10": "7.1.11",
|
||||||
"@sveltejs/kit@>=2.0.0 <2.20.6": ">=2.20.6",
|
"@sveltejs/kit@>=2.0.0 <2.20.6": ">=2.20.6",
|
||||||
"react-router@<7.5.2": ">=7.5.2",
|
"react-router@<7.5.2": ">=7.5.2",
|
||||||
"undici@<5.29.0": ">=5.29.0",
|
"undici@<5.29.0": ">=5.29.0",
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import { expect, test } from "@jest/globals";
|
import { expect, test } from "@jest/globals";
|
||||||
import { createClient } from "@nhost/nhost-js";
|
import {
|
||||||
|
createClient,
|
||||||
|
createNhostClient,
|
||||||
|
withAdminSession,
|
||||||
|
} from "@nhost/nhost-js";
|
||||||
|
|
||||||
const subdomain = "local";
|
const subdomain = "local";
|
||||||
const region = "local";
|
const region = "local";
|
||||||
@@ -44,7 +48,7 @@ test("mainExample", async () => {
|
|||||||
// "updatedAt": "2025-05-09T17:26:04.589692+00:00",
|
// "updatedAt": "2025-05-09T17:26:04.589692+00:00",
|
||||||
// "isUploaded": true,
|
// "isUploaded": true,
|
||||||
// "mimeType": "text/plain",
|
// "mimeType": "text/plain",
|
||||||
// "uploadedByUserId": "",
|
// "uploadedByUserId": "3357aada-b6c7-4af1-9655-1307ca2883a2",
|
||||||
// "metadata": null
|
// "metadata": null
|
||||||
// },
|
// },
|
||||||
// {
|
// {
|
||||||
@@ -57,7 +61,133 @@ test("mainExample", async () => {
|
|||||||
// "updatedAt": "2025-05-09T17:26:04.596831+00:00",
|
// "updatedAt": "2025-05-09T17:26:04.596831+00:00",
|
||||||
// "isUploaded": true,
|
// "isUploaded": true,
|
||||||
// "mimeType": "text/plain",
|
// "mimeType": "text/plain",
|
||||||
// "uploadedByUserId": "",
|
// "uploadedByUserId": "3357aada-b6c7-4af1-9655-1307ca2883a2",
|
||||||
|
// "metadata": null
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// },
|
||||||
|
// "status": 201,
|
||||||
|
// "headers": {
|
||||||
|
// "content-length": "644",
|
||||||
|
// "content-type": "application/json; charset=utf-8",
|
||||||
|
// "date": "Fri, 09 May 2025 17:26:04 GMT"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// make a GraphQL request to list the files
|
||||||
|
const graphResp = await nhost.graphql.request({
|
||||||
|
query: `
|
||||||
|
query {
|
||||||
|
files {
|
||||||
|
name
|
||||||
|
size
|
||||||
|
mimeType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(JSON.stringify(graphResp, null, 2));
|
||||||
|
// {
|
||||||
|
// "body": {
|
||||||
|
// "data": {
|
||||||
|
// "files": [
|
||||||
|
// {
|
||||||
|
// "name": "file-1",
|
||||||
|
// "size": 5,
|
||||||
|
// "mimeType": "text/plain"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "file-2",
|
||||||
|
// "size": 15,
|
||||||
|
// "mimeType": "text/plain"
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "status": 200,
|
||||||
|
// "headers": {}
|
||||||
|
// }
|
||||||
|
|
||||||
|
// make a request to a serverless function
|
||||||
|
const funcResp = await nhost.functions.post("/helloworld", {
|
||||||
|
message: "Hello, World!",
|
||||||
|
});
|
||||||
|
console.log(JSON.stringify(funcResp.body, null, 2));
|
||||||
|
// {
|
||||||
|
// "message": "Hello, World!"
|
||||||
|
// }
|
||||||
|
|
||||||
|
expect(uplFilesResp.status).toBe(201);
|
||||||
|
|
||||||
|
expect(graphResp.status).toBe(200);
|
||||||
|
expect(graphResp.body.errors).toBeUndefined();
|
||||||
|
expect(graphResp.body.data).toStrictEqual({
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
name: "file-1",
|
||||||
|
size: 5,
|
||||||
|
mimeType: "text/plain",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "file-2",
|
||||||
|
size: 15,
|
||||||
|
mimeType: "text/plain",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("adminClient", async () => {
|
||||||
|
const nhost = createNhostClient({
|
||||||
|
subdomain,
|
||||||
|
region,
|
||||||
|
configure: [
|
||||||
|
withAdminSession({
|
||||||
|
adminSecret: "nhost-admin-secret",
|
||||||
|
role: "user",
|
||||||
|
sessionVariables: {
|
||||||
|
"user-id": "54058C42-51F7-4B37-8B69-C89A841D2221",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// upload a couple of files
|
||||||
|
const uplFilesResp = await nhost.storage.uploadFiles({
|
||||||
|
"file[]": [
|
||||||
|
new File(["test1"], "file-1", { type: "text/plain" }),
|
||||||
|
new File(["test2 is larger"], "file-2", { type: "text/plain" }),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
console.log(JSON.stringify(uplFilesResp, null, 2));
|
||||||
|
// {
|
||||||
|
// "data": {
|
||||||
|
// "processedFiles": [
|
||||||
|
// {
|
||||||
|
// "id": "c0e83185-0ce5-435c-bd46-9841adc30699",
|
||||||
|
// "name": "file-1",
|
||||||
|
// "size": 5,
|
||||||
|
// "bucketId": "default",
|
||||||
|
// "etag": "\"5a105e8b9d40e1329780d62ea2265d8a\"",
|
||||||
|
// "createdAt": "2025-05-09T17:26:04.579839+00:00",
|
||||||
|
// "updatedAt": "2025-05-09T17:26:04.589692+00:00",
|
||||||
|
// "isUploaded": true,
|
||||||
|
// "mimeType": "text/plain",
|
||||||
|
// "uploadedByUserId": "54058c42-51f7-4b37-8b69-c89a841d2221",
|
||||||
|
// "metadata": null
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": "3f189004-21fd-42d0-be1d-1ead021ab167",
|
||||||
|
// "name": "file-2",
|
||||||
|
// "size": 15,
|
||||||
|
// "bucketId": "default",
|
||||||
|
// "etag": "\"302e888c5e289fe6b02115b748771ee9\"",
|
||||||
|
// "createdAt": "2025-05-09T17:26:04.59245+00:00",
|
||||||
|
// "updatedAt": "2025-05-09T17:26:04.596831+00:00",
|
||||||
|
// "isUploaded": true,
|
||||||
|
// "mimeType": "text/plain",
|
||||||
|
// "uploadedByUserId": "54058c42-51f7-4b37-8b69-c89a841d2221",
|
||||||
// "metadata": null
|
// "metadata": null
|
||||||
// }
|
// }
|
||||||
// ]
|
// ]
|
||||||
|
|||||||
@@ -45,3 +45,22 @@ export { sessionRefreshMiddleware } from "./middlewareSessionRefresh";
|
|||||||
* @returns A middleware function that updates session storage
|
* @returns A middleware function that updates session storage
|
||||||
*/
|
*/
|
||||||
export { updateSessionFromResponseMiddleware } from "./middlewareUpdateSessionFromResponse";
|
export { updateSessionFromResponseMiddleware } from "./middlewareUpdateSessionFromResponse";
|
||||||
|
/**
|
||||||
|
* Middleware for attaching Hasura admin secret for elevated permissions.
|
||||||
|
*
|
||||||
|
* @param options - Admin session options including the admin secret
|
||||||
|
* @returns A middleware function that adds x-hasura-admin-secret header
|
||||||
|
*/
|
||||||
|
export {
|
||||||
|
type AdminSessionOptions,
|
||||||
|
withAdminSessionMiddleware,
|
||||||
|
} from "./middlewareWithAdminSession";
|
||||||
|
export { withHeadersMiddleware } from "./middlewareWithHeaders";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Middleware for setting the Hasura role header for requests.
|
||||||
|
*
|
||||||
|
* @param role - The Hasura role to use for requests
|
||||||
|
* @returns A middleware function that adds x-hasura-role header
|
||||||
|
*/
|
||||||
|
export { withRoleMiddleware } from "./middlewareWithRole";
|
||||||
|
|||||||
121
packages/nhost-js/src/fetch/middlewareWithAdminSession.ts
Normal file
121
packages/nhost-js/src/fetch/middlewareWithAdminSession.ts
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
/**
|
||||||
|
* Admin session middleware for the Nhost SDK.
|
||||||
|
*
|
||||||
|
* This module provides middleware functionality to automatically attach
|
||||||
|
* Hasura admin secret for admin permissions in requests.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { ChainFunction, FetchFunction } from "./fetch";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration options for admin session middleware
|
||||||
|
*/
|
||||||
|
export interface AdminSessionOptions {
|
||||||
|
/**
|
||||||
|
* Hasura admin secret for elevated permissions (sets x-hasura-admin-secret header)
|
||||||
|
*/
|
||||||
|
adminSecret: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hasura role to use for the request (sets x-hasura-role header)
|
||||||
|
*/
|
||||||
|
role?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Additional Hasura session variables to attach to requests.
|
||||||
|
* Keys will be automatically prefixed with 'x-hasura-' if not already present.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* {
|
||||||
|
* 'user-id': '123',
|
||||||
|
* 'org-id': '456'
|
||||||
|
* }
|
||||||
|
* // Results in headers:
|
||||||
|
* // x-hasura-user-id: 123
|
||||||
|
* // x-hasura-org-id: 456
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
sessionVariables?: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a fetch middleware that attaches the Hasura admin secret and optional session variables to requests.
|
||||||
|
*
|
||||||
|
* This middleware:
|
||||||
|
* 1. Sets the x-hasura-admin-secret header, which grants full admin access to Hasura
|
||||||
|
* 2. Optionally sets the x-hasura-role header if a role is provided
|
||||||
|
* 3. Optionally sets additional x-hasura-* headers for custom session variables
|
||||||
|
*
|
||||||
|
* **Security Warning**: Never use this middleware in client-side code or expose
|
||||||
|
* the admin secret to end users. Admin secrets grant unrestricted access to your
|
||||||
|
* entire database. This should only be used in trusted server-side environments.
|
||||||
|
*
|
||||||
|
* The middleware preserves request-specific headers when they conflict with the
|
||||||
|
* admin session configuration.
|
||||||
|
*
|
||||||
|
* @param options - Admin session options including admin secret, role, and session variables
|
||||||
|
* @returns A middleware function that can be used in the fetch chain
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* // Create middleware with admin secret only
|
||||||
|
* const adminMiddleware = withAdminSessionMiddleware({
|
||||||
|
* adminSecret: process.env.NHOST_ADMIN_SECRET
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* // Create middleware with admin secret and role
|
||||||
|
* const adminUserMiddleware = withAdminSessionMiddleware({
|
||||||
|
* adminSecret: process.env.NHOST_ADMIN_SECRET,
|
||||||
|
* role: 'user'
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* // Create middleware with admin secret, role, and custom session variables
|
||||||
|
* const fullMiddleware = withAdminSessionMiddleware({
|
||||||
|
* adminSecret: process.env.NHOST_ADMIN_SECRET,
|
||||||
|
* role: 'user',
|
||||||
|
* sessionVariables: {
|
||||||
|
* 'user-id': '123',
|
||||||
|
* 'org-id': '456'
|
||||||
|
* }
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* // Use with createCustomClient for an admin client
|
||||||
|
* const adminClient = createCustomClient({
|
||||||
|
* subdomain: 'myproject',
|
||||||
|
* region: 'eu-central-1',
|
||||||
|
* chainFunctions: [adminMiddleware]
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export const withAdminSessionMiddleware =
|
||||||
|
(options: AdminSessionOptions): ChainFunction =>
|
||||||
|
(next: FetchFunction): FetchFunction =>
|
||||||
|
async (url: string, requestOptions: RequestInit = {}): Promise<Response> => {
|
||||||
|
const headers = new Headers(requestOptions.headers || {});
|
||||||
|
|
||||||
|
// Set x-hasura-admin-secret if not already present
|
||||||
|
if (!headers.has("x-hasura-admin-secret")) {
|
||||||
|
headers.set("x-hasura-admin-secret", options.adminSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set x-hasura-role if provided and not already present
|
||||||
|
if (options.role && !headers.has("x-hasura-role")) {
|
||||||
|
headers.set("x-hasura-role", options.role);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set custom session variables
|
||||||
|
if (options.sessionVariables) {
|
||||||
|
for (const [key, value] of Object.entries(options.sessionVariables)) {
|
||||||
|
// Ensure the key has the x-hasura- prefix
|
||||||
|
const headerKey = key.startsWith("x-hasura-") ? key : `x-hasura-${key}`;
|
||||||
|
|
||||||
|
// Only set if not already present in the request
|
||||||
|
if (!headers.has(headerKey)) {
|
||||||
|
headers.set(headerKey, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return next(url, { ...requestOptions, headers });
|
||||||
|
};
|
||||||
38
packages/nhost-js/src/fetch/middlewareWithHeaders.ts
Normal file
38
packages/nhost-js/src/fetch/middlewareWithHeaders.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* Headers middleware for the Nhost SDK.
|
||||||
|
*
|
||||||
|
* This module provides middleware functionality to automatically attach
|
||||||
|
* default headers to all outgoing requests, while allowing request-specific
|
||||||
|
* headers to take precedence.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { ChainFunction, FetchFunction } from "./fetch";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a fetch middleware that attaches default headers to requests.
|
||||||
|
*
|
||||||
|
* This middleware:
|
||||||
|
* 1. Merges default headers with request-specific headers
|
||||||
|
* 2. Preserves request-specific headers when they conflict with defaults
|
||||||
|
*
|
||||||
|
* The middleware ensures consistent headers across requests while allowing
|
||||||
|
* individual requests to override defaults as needed.
|
||||||
|
*
|
||||||
|
* @param defaultHeaders - Default headers to attach to all requests
|
||||||
|
* @returns A middleware function that can be used in the fetch chain
|
||||||
|
*/
|
||||||
|
export const withHeadersMiddleware =
|
||||||
|
(defaultHeaders: HeadersInit): ChainFunction =>
|
||||||
|
(next: FetchFunction): FetchFunction =>
|
||||||
|
async (url: string, options: RequestInit = {}): Promise<Response> => {
|
||||||
|
const headers = new Headers(options.headers || {});
|
||||||
|
const defaults = new Headers(defaultHeaders);
|
||||||
|
|
||||||
|
defaults.forEach((value, key) => {
|
||||||
|
if (!headers.has(key)) {
|
||||||
|
headers.set(key, value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return next(url, { ...options, headers });
|
||||||
|
};
|
||||||
57
packages/nhost-js/src/fetch/middlewareWithRole.ts
Normal file
57
packages/nhost-js/src/fetch/middlewareWithRole.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* Role middleware for the Nhost SDK.
|
||||||
|
*
|
||||||
|
* This module provides middleware functionality to automatically set
|
||||||
|
* the Hasura role for all requests. This is useful when you want to
|
||||||
|
* make requests as a specific role without using the admin secret.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { ChainFunction, FetchFunction } from "./fetch";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a fetch middleware that sets the Hasura role header.
|
||||||
|
*
|
||||||
|
* This middleware sets the x-hasura-role header for all requests, allowing
|
||||||
|
* you to specify which role's permissions should be used. This works with
|
||||||
|
* authenticated sessions where the user has access to the specified role.
|
||||||
|
*
|
||||||
|
* Unlike `withAdminSessionMiddleware`, this does not bypass permission rules
|
||||||
|
* but instead uses the permission rules defined for the specified role.
|
||||||
|
*
|
||||||
|
* The middleware preserves request-specific headers when they conflict with
|
||||||
|
* the role configuration.
|
||||||
|
*
|
||||||
|
* @param role - The Hasura role to use for requests
|
||||||
|
* @returns A middleware function that can be used in the fetch chain
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* // Use with createClient to default all requests to a specific role
|
||||||
|
* const nhost = createClient({
|
||||||
|
* subdomain: 'myproject',
|
||||||
|
* region: 'eu-central-1',
|
||||||
|
* chainFunctions: [withRoleMiddleware('moderator')]
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* // Use with createServerClient for server-side requests
|
||||||
|
* const serverNhost = createServerClient({
|
||||||
|
* subdomain: 'myproject',
|
||||||
|
* region: 'eu-central-1',
|
||||||
|
* storage: myServerStorage,
|
||||||
|
* chainFunctions: [withRoleMiddleware('moderator')]
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export const withRoleMiddleware =
|
||||||
|
(role: string): ChainFunction =>
|
||||||
|
(next: FetchFunction): FetchFunction =>
|
||||||
|
async (url: string, requestOptions: RequestInit = {}): Promise<Response> => {
|
||||||
|
const headers = new Headers(requestOptions.headers || {});
|
||||||
|
|
||||||
|
// Set x-hasura-role if not already present
|
||||||
|
if (!headers.has("x-hasura-role")) {
|
||||||
|
headers.set("x-hasura-role", role);
|
||||||
|
}
|
||||||
|
|
||||||
|
return next(url, { ...requestOptions, headers });
|
||||||
|
};
|
||||||
@@ -17,17 +17,32 @@
|
|||||||
*
|
*
|
||||||
* Create a client instance to interact with Nhost services:
|
* Create a client instance to interact with Nhost services:
|
||||||
*
|
*
|
||||||
* {@includeCode ./__tests__/docstrings.test.ts:11-115}
|
* {@includeCode ./__tests__/docstrings.test.ts:15-119}
|
||||||
|
*
|
||||||
|
* ### Creating an admin client
|
||||||
|
*
|
||||||
|
* You can also create an admin client if needed. This client will have admin access to the database
|
||||||
|
* and will bypass permissions. Additionally, it can impersonate users and set any role or session
|
||||||
|
* variable.
|
||||||
|
*
|
||||||
|
* IMPORTANT!!! Keep your admin secret safe and never expose it in client-side code.
|
||||||
|
*
|
||||||
|
* {@includeCode ./__tests__/docstrings.test.ts:142-201}
|
||||||
*
|
*
|
||||||
* @packageDocumentation
|
* @packageDocumentation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
type ClientConfigurationFn,
|
||||||
createClient,
|
createClient,
|
||||||
|
createNhostClient,
|
||||||
createServerClient,
|
createServerClient,
|
||||||
type NhostClient,
|
type NhostClient,
|
||||||
type NhostClientOptions,
|
type NhostClientOptions,
|
||||||
type NhostServerClientOptions,
|
type NhostServerClientOptions,
|
||||||
|
withAdminSession,
|
||||||
|
withClientSideSessionMiddleware,
|
||||||
|
withServerSideSessionMiddleware,
|
||||||
} from "./nhost";
|
} from "./nhost";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,10 +4,12 @@ import {
|
|||||||
createAPIClient as createAuthClient,
|
createAPIClient as createAuthClient,
|
||||||
} from "./auth";
|
} from "./auth";
|
||||||
import {
|
import {
|
||||||
|
type AdminSessionOptions,
|
||||||
attachAccessTokenMiddleware,
|
attachAccessTokenMiddleware,
|
||||||
type ChainFunction,
|
type ChainFunction,
|
||||||
sessionRefreshMiddleware,
|
sessionRefreshMiddleware,
|
||||||
updateSessionFromResponseMiddleware,
|
updateSessionFromResponseMiddleware,
|
||||||
|
withAdminSessionMiddleware,
|
||||||
} from "./fetch";
|
} from "./fetch";
|
||||||
import {
|
import {
|
||||||
createAPIClient as createFunctionsClient,
|
createAPIClient as createFunctionsClient,
|
||||||
@@ -29,6 +31,110 @@ import {
|
|||||||
type Client as StorageClient,
|
type Client as StorageClient,
|
||||||
} from "./storage";
|
} from "./storage";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration function that receives all clients and can configure them
|
||||||
|
* (e.g., by attaching middleware, setting up interceptors, etc.)
|
||||||
|
*/
|
||||||
|
export type ClientConfigurationFn = (clients: {
|
||||||
|
auth: AuthClient;
|
||||||
|
storage: StorageClient;
|
||||||
|
graphql: GraphQLClient;
|
||||||
|
functions: FunctionsClient;
|
||||||
|
sessionStorage: SessionStorage;
|
||||||
|
}) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Built-in configuration for client-side applications.
|
||||||
|
* Includes automatic session refresh, token attachment, and session updates.
|
||||||
|
*/
|
||||||
|
export const withClientSideSessionMiddleware: ClientConfigurationFn = ({
|
||||||
|
auth,
|
||||||
|
storage,
|
||||||
|
graphql,
|
||||||
|
functions,
|
||||||
|
sessionStorage,
|
||||||
|
}) => {
|
||||||
|
const mwChain: ChainFunction[] = [
|
||||||
|
sessionRefreshMiddleware(auth, sessionStorage),
|
||||||
|
updateSessionFromResponseMiddleware(sessionStorage),
|
||||||
|
attachAccessTokenMiddleware(sessionStorage),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const mw of mwChain) {
|
||||||
|
auth.pushChainFunction(mw);
|
||||||
|
storage.pushChainFunction(mw);
|
||||||
|
graphql.pushChainFunction(mw);
|
||||||
|
functions.pushChainFunction(mw);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Built-in configuration for server-side applications.
|
||||||
|
* Includes token attachment and session updates, but NOT automatic session refresh
|
||||||
|
* to prevent race conditions in server contexts.
|
||||||
|
*/
|
||||||
|
export const withServerSideSessionMiddleware: ClientConfigurationFn = ({
|
||||||
|
auth,
|
||||||
|
storage,
|
||||||
|
graphql,
|
||||||
|
functions,
|
||||||
|
sessionStorage,
|
||||||
|
}) => {
|
||||||
|
const mwChain: ChainFunction[] = [
|
||||||
|
updateSessionFromResponseMiddleware(sessionStorage),
|
||||||
|
attachAccessTokenMiddleware(sessionStorage),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const mw of mwChain) {
|
||||||
|
auth.pushChainFunction(mw);
|
||||||
|
storage.pushChainFunction(mw);
|
||||||
|
graphql.pushChainFunction(mw);
|
||||||
|
functions.pushChainFunction(mw);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for admin clients with elevated privileges.
|
||||||
|
* Applies admin session middleware to storage, graphql, and functions clients only.
|
||||||
|
*
|
||||||
|
* **Security Warning**: Never use this in client-side code. Admin secrets grant
|
||||||
|
* unrestricted access to your entire database.
|
||||||
|
*
|
||||||
|
* @param adminSession - Admin session options including admin secret, role, and session variables
|
||||||
|
* @returns Configuration function that sets up admin middleware
|
||||||
|
*/
|
||||||
|
export function withAdminSession(
|
||||||
|
adminSession: AdminSessionOptions,
|
||||||
|
): ClientConfigurationFn {
|
||||||
|
return ({ storage, graphql, functions }) => {
|
||||||
|
const adminMiddleware = withAdminSessionMiddleware(adminSession);
|
||||||
|
|
||||||
|
storage.pushChainFunction(adminMiddleware);
|
||||||
|
graphql.pushChainFunction(adminMiddleware);
|
||||||
|
functions.pushChainFunction(adminMiddleware);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for adding custom chain functions to all clients.
|
||||||
|
* Useful for adding custom middleware like logging, caching, or custom headers.
|
||||||
|
*
|
||||||
|
* @param chainFunctions - Array of chain functions to apply to all clients
|
||||||
|
* @returns Configuration function that sets up custom middleware
|
||||||
|
*/
|
||||||
|
export function withChainFunctions(
|
||||||
|
chainFunctions: ChainFunction[],
|
||||||
|
): ClientConfigurationFn {
|
||||||
|
return ({ auth, storage, graphql, functions }) => {
|
||||||
|
for (const mw of chainFunctions) {
|
||||||
|
auth.pushChainFunction(mw);
|
||||||
|
storage.pushChainFunction(mw);
|
||||||
|
graphql.pushChainFunction(mw);
|
||||||
|
functions.pushChainFunction(mw);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main client class that provides unified access to all Nhost services.
|
* Main client class that provides unified access to all Nhost services.
|
||||||
* This class serves as the central interface for interacting with Nhost's
|
* This class serves as the central interface for interacting with Nhost's
|
||||||
@@ -192,6 +298,122 @@ export interface NhostClientOptions {
|
|||||||
* default to localStorage in the browser or memory in other environments.
|
* default to localStorage in the browser or memory in other environments.
|
||||||
*/
|
*/
|
||||||
storage?: SessionStorageBackend;
|
storage?: SessionStorageBackend;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration functions to be applied to the client after initialization.
|
||||||
|
* These functions receive all clients and can attach middleware or perform other setup.
|
||||||
|
*/
|
||||||
|
configure?: ClientConfigurationFn[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and configures a new Nhost client instance with custom configuration.
|
||||||
|
*
|
||||||
|
* This is the main factory function for creating Nhost clients. It instantiates
|
||||||
|
* all service clients (auth, storage, graphql, functions) and applies the provided
|
||||||
|
* configuration functions to set up middleware and other customizations.
|
||||||
|
*
|
||||||
|
* @param options - Configuration options for the client
|
||||||
|
* @returns A configured Nhost client
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* // Create a basic client with no middleware
|
||||||
|
* const nhost = createNhostClient({
|
||||||
|
* subdomain: 'abcdefgh',
|
||||||
|
* region: 'eu-central-1',
|
||||||
|
* configure: []
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* // Create a client with custom configuration
|
||||||
|
* const nhost = createNhostClient({
|
||||||
|
* subdomain: 'abcdefgh',
|
||||||
|
* region: 'eu-central-1',
|
||||||
|
* configure: [
|
||||||
|
* withClientSideSessionMiddleware,
|
||||||
|
* withChainFunctions([customLoggingMiddleware])
|
||||||
|
* ]
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* // Create an admin client
|
||||||
|
* const nhost = createNhostClient({
|
||||||
|
* subdomain,
|
||||||
|
* region,
|
||||||
|
* configure: [
|
||||||
|
* withAdminSession({
|
||||||
|
* adminSecret: "nhost-admin-secret",
|
||||||
|
* role: "user",
|
||||||
|
* sessionVariables: {
|
||||||
|
* "user-id": "54058C42-51F7-4B37-8B69-C89A841D2221",
|
||||||
|
* },
|
||||||
|
* }),
|
||||||
|
* ],
|
||||||
|
* });
|
||||||
|
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export function createNhostClient(
|
||||||
|
options: NhostClientOptions = {},
|
||||||
|
): NhostClient {
|
||||||
|
const {
|
||||||
|
subdomain,
|
||||||
|
region,
|
||||||
|
authUrl,
|
||||||
|
storageUrl,
|
||||||
|
graphqlUrl,
|
||||||
|
functionsUrl,
|
||||||
|
storage = detectStorage(),
|
||||||
|
configure = [],
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
const sessionStorage = new SessionStorage(storage);
|
||||||
|
|
||||||
|
// Determine base URLs for each service
|
||||||
|
const authBaseUrl = generateServiceUrl("auth", subdomain, region, authUrl);
|
||||||
|
const storageBaseUrl = generateServiceUrl(
|
||||||
|
"storage",
|
||||||
|
subdomain,
|
||||||
|
region,
|
||||||
|
storageUrl,
|
||||||
|
);
|
||||||
|
const graphqlBaseUrl = generateServiceUrl(
|
||||||
|
"graphql",
|
||||||
|
subdomain,
|
||||||
|
region,
|
||||||
|
graphqlUrl,
|
||||||
|
);
|
||||||
|
const functionsBaseUrl = generateServiceUrl(
|
||||||
|
"functions",
|
||||||
|
subdomain,
|
||||||
|
region,
|
||||||
|
functionsUrl,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create all clients
|
||||||
|
const auth = createAuthClient(authBaseUrl);
|
||||||
|
const storageClient = createStorageClient(storageBaseUrl, []);
|
||||||
|
const graphqlClient = createGraphQLClient(graphqlBaseUrl, []);
|
||||||
|
const functionsClient = createFunctionsClient(functionsBaseUrl, []);
|
||||||
|
|
||||||
|
// Apply configuration functions
|
||||||
|
for (const configFn of configure) {
|
||||||
|
configFn({
|
||||||
|
auth,
|
||||||
|
storage: storageClient,
|
||||||
|
graphql: graphqlClient,
|
||||||
|
functions: functionsClient,
|
||||||
|
sessionStorage,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return an initialized NhostClient
|
||||||
|
return new NhostClient(
|
||||||
|
auth,
|
||||||
|
storageClient,
|
||||||
|
graphqlClient,
|
||||||
|
functionsClient,
|
||||||
|
sessionStorage,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -237,65 +459,23 @@ export interface NhostClientOptions {
|
|||||||
* secure: import.meta.env.ENVIRONMENT === 'production',
|
* secure: import.meta.env.ENVIRONMENT === 'production',
|
||||||
* })
|
* })
|
||||||
* });
|
* });
|
||||||
|
*
|
||||||
|
* // Create client with additional custom middleware
|
||||||
|
* const nhost = createClient({
|
||||||
|
* subdomain: 'abcdefgh',
|
||||||
|
* region: 'eu-central-1',
|
||||||
|
* configure: [customLoggingMiddleware]
|
||||||
|
* });
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export function createClient(options: NhostClientOptions = {}): NhostClient {
|
export function createClient(options: NhostClientOptions = {}): NhostClient {
|
||||||
const {
|
const storage = options.storage ?? detectStorage();
|
||||||
subdomain,
|
|
||||||
region,
|
|
||||||
authUrl,
|
|
||||||
storageUrl,
|
|
||||||
graphqlUrl,
|
|
||||||
functionsUrl,
|
|
||||||
storage = detectStorage(),
|
|
||||||
} = options;
|
|
||||||
|
|
||||||
const sessionStorage = new SessionStorage(storage);
|
return createNhostClient({
|
||||||
|
...options,
|
||||||
// Determine base URLs for each service
|
storage,
|
||||||
const authBaseUrl = generateServiceUrl("auth", subdomain, region, authUrl);
|
configure: [withClientSideSessionMiddleware, ...(options.configure ?? [])],
|
||||||
const storageBaseUrl = generateServiceUrl(
|
});
|
||||||
"storage",
|
|
||||||
subdomain,
|
|
||||||
region,
|
|
||||||
storageUrl,
|
|
||||||
);
|
|
||||||
const graphqlBaseUrl = generateServiceUrl(
|
|
||||||
"graphql",
|
|
||||||
subdomain,
|
|
||||||
region,
|
|
||||||
graphqlUrl,
|
|
||||||
);
|
|
||||||
|
|
||||||
const functionsBaseUrl = generateServiceUrl(
|
|
||||||
"functions",
|
|
||||||
subdomain,
|
|
||||||
region,
|
|
||||||
functionsUrl,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create auth client
|
|
||||||
const auth = createAuthClient(authBaseUrl);
|
|
||||||
|
|
||||||
const mwChain = getMiddlewareChain(auth, sessionStorage, true);
|
|
||||||
|
|
||||||
for (const mw of mwChain) {
|
|
||||||
auth.pushChainFunction(mw);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create storage and graphql clients with the refresh and attach token middlewares
|
|
||||||
const storageClient = createStorageClient(storageBaseUrl, mwChain);
|
|
||||||
const graphqlClient = createGraphQLClient(graphqlBaseUrl, mwChain);
|
|
||||||
const functionsClient = createFunctionsClient(functionsBaseUrl, mwChain);
|
|
||||||
|
|
||||||
// Return an initialized NhostClient
|
|
||||||
return new NhostClient(
|
|
||||||
auth,
|
|
||||||
storageClient,
|
|
||||||
graphqlClient,
|
|
||||||
functionsClient,
|
|
||||||
sessionStorage,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NhostServerClientOptions extends NhostClientOptions {
|
export interface NhostServerClientOptions extends NhostClientOptions {
|
||||||
@@ -414,81 +594,21 @@ export interface NhostServerClientOptions extends NhostClientOptions {
|
|||||||
* },
|
* },
|
||||||
* });
|
* });
|
||||||
* };
|
* };
|
||||||
|
*
|
||||||
|
* // Example with additional custom middleware
|
||||||
|
* const nhost = createServerClient({
|
||||||
|
* region: process.env["NHOST_REGION"] || "local",
|
||||||
|
* subdomain: process.env["NHOST_SUBDOMAIN"] || "local",
|
||||||
|
* storage: myStorage,
|
||||||
|
* configure: [customLoggingMiddleware]
|
||||||
|
* });
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export function createServerClient(
|
export function createServerClient(
|
||||||
options: NhostServerClientOptions,
|
options: NhostServerClientOptions,
|
||||||
): NhostClient {
|
): NhostClient {
|
||||||
const {
|
return createNhostClient({
|
||||||
subdomain,
|
...options,
|
||||||
region,
|
configure: [withServerSideSessionMiddleware, ...(options.configure ?? [])],
|
||||||
authUrl,
|
});
|
||||||
storageUrl,
|
|
||||||
graphqlUrl,
|
|
||||||
functionsUrl,
|
|
||||||
storage,
|
|
||||||
} = options;
|
|
||||||
const sessionStorage = new SessionStorage(storage);
|
|
||||||
|
|
||||||
// Determine base URLs for each service
|
|
||||||
const authBaseUrl = generateServiceUrl("auth", subdomain, region, authUrl);
|
|
||||||
const storageBaseUrl = generateServiceUrl(
|
|
||||||
"storage",
|
|
||||||
subdomain,
|
|
||||||
region,
|
|
||||||
storageUrl,
|
|
||||||
);
|
|
||||||
const graphqlBaseUrl = generateServiceUrl(
|
|
||||||
"graphql",
|
|
||||||
subdomain,
|
|
||||||
region,
|
|
||||||
graphqlUrl,
|
|
||||||
);
|
|
||||||
|
|
||||||
const functionsBaseUrl = generateServiceUrl(
|
|
||||||
"functions",
|
|
||||||
subdomain,
|
|
||||||
region,
|
|
||||||
functionsUrl,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create auth client
|
|
||||||
const auth = createAuthClient(authBaseUrl);
|
|
||||||
|
|
||||||
const mwChain = getMiddlewareChain(auth, sessionStorage, false);
|
|
||||||
|
|
||||||
for (const mw of mwChain) {
|
|
||||||
auth.pushChainFunction(mw);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create storage and graphql clients with the refresh and attach token middlewares
|
|
||||||
const storageClient = createStorageClient(storageBaseUrl, mwChain);
|
|
||||||
const graphqlClient = createGraphQLClient(graphqlBaseUrl, mwChain);
|
|
||||||
const functionsClient = createFunctionsClient(functionsBaseUrl, mwChain);
|
|
||||||
|
|
||||||
// Return an initialized NhostClient
|
|
||||||
return new NhostClient(
|
|
||||||
auth,
|
|
||||||
storageClient,
|
|
||||||
graphqlClient,
|
|
||||||
functionsClient,
|
|
||||||
sessionStorage,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMiddlewareChain(
|
|
||||||
auth: AuthClient,
|
|
||||||
storage: SessionStorage,
|
|
||||||
autoRefresh: boolean,
|
|
||||||
): ChainFunction[] {
|
|
||||||
const mwChain = [
|
|
||||||
updateSessionFromResponseMiddleware(storage),
|
|
||||||
attachAccessTokenMiddleware(storage),
|
|
||||||
];
|
|
||||||
|
|
||||||
if (autoRefresh) {
|
|
||||||
mwChain.unshift(sessionRefreshMiddleware(auth, storage));
|
|
||||||
}
|
|
||||||
|
|
||||||
return mwChain;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ interface Lock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const lock: Lock =
|
const lock: Lock =
|
||||||
|
// biome-ignore lint/complexity/useOptionalChain: this check breaks non-browser environments
|
||||||
typeof navigator !== "undefined" && navigator.locks
|
typeof navigator !== "undefined" && navigator.locks
|
||||||
? navigator.locks
|
? navigator.locks
|
||||||
: new DummyLock();
|
: new DummyLock();
|
||||||
|
|||||||
28
pnpm-lock.yaml
generated
28
pnpm-lock.yaml
generated
@@ -25,7 +25,6 @@ overrides:
|
|||||||
zod@<=3.22.2: '>=3.22.3'
|
zod@<=3.22.2: '>=3.22.3'
|
||||||
'@antfu/utils@<0.7.3': '>=0.7.3'
|
'@antfu/utils@<0.7.3': '>=0.7.3'
|
||||||
next@>=0.9.9 <13.4.20-canary.13: '>=13.4.20-canary.13'
|
next@>=0.9.9 <13.4.20-canary.13: '>=13.4.20-canary.13'
|
||||||
vite@<=4.5.13: '>=4.5.14'
|
|
||||||
yaml@>=2.0.0-5 <2.2.2: '>=2.2.2'
|
yaml@>=2.0.0-5 <2.2.2: '>=2.2.2'
|
||||||
pnpm@<7.33.4: '>=7.33.4'
|
pnpm@<7.33.4: '>=7.33.4'
|
||||||
graphql@>=16.3.0 <16.8.1: '>=16.8.1'
|
graphql@>=16.3.0 <16.8.1: '>=16.8.1'
|
||||||
@@ -74,8 +73,11 @@ overrides:
|
|||||||
cookie@<0.7.0: '>=0.7.0'
|
cookie@<0.7.0: '>=0.7.0'
|
||||||
prismjs@<1.30.0: '>=1.30.0'
|
prismjs@<1.30.0: '>=1.30.0'
|
||||||
axios@<1.8.2: '>=1.8.2'
|
axios@<1.8.2: '>=1.8.2'
|
||||||
vite@>=5.0.0 <=5.4.18: '>=5.4.19'
|
vite@<=4.5.13: '>=4.5.14'
|
||||||
vite@>=6.2.0 <=6.2.6: '>=6.2.6'
|
vite@>=5.0.0 <=5.4.20: '>=5.4.21'
|
||||||
|
vite@>=6.0.0 <=6.4.0: '>=6.4.1'
|
||||||
|
vite@>=7.0.0 <=7.0.7: 7.0.8
|
||||||
|
vite@>=7.1.0 <=7.1.10: 7.1.11
|
||||||
'@sveltejs/kit@>=2.0.0 <2.20.6': '>=2.20.6'
|
'@sveltejs/kit@>=2.0.0 <2.20.6': '>=2.20.6'
|
||||||
react-router@<7.5.2: '>=7.5.2'
|
react-router@<7.5.2: '>=7.5.2'
|
||||||
undici@<5.29.0: '>=5.29.0'
|
undici@<5.29.0: '>=5.29.0'
|
||||||
@@ -103,11 +105,11 @@ importers:
|
|||||||
specifier: 5.8.3
|
specifier: 5.8.3
|
||||||
version: 5.8.3
|
version: 5.8.3
|
||||||
vite:
|
vite:
|
||||||
specifier: ^5.4.20
|
specifier: ^5.4.21
|
||||||
version: 5.4.20(@types/node@24.3.1)
|
version: 5.4.21(@types/node@24.3.1)
|
||||||
vite-tsconfig-paths:
|
vite-tsconfig-paths:
|
||||||
specifier: ^4.3.2
|
specifier: ^4.3.2
|
||||||
version: 4.3.2(typescript@5.8.3)(vite@5.4.20(@types/node@24.3.1))
|
version: 4.3.2(typescript@5.8.3)(vite@5.4.21(@types/node@24.3.1))
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^0.32.4
|
specifier: ^0.32.4
|
||||||
version: 0.32.4
|
version: 0.32.4
|
||||||
@@ -750,8 +752,8 @@ packages:
|
|||||||
vite:
|
vite:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
vite@5.4.20:
|
vite@5.4.21:
|
||||||
resolution: {integrity: sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==}
|
resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==}
|
||||||
engines: {node: ^18.0.0 || >=20.0.0}
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -1362,7 +1364,7 @@ snapshots:
|
|||||||
mlly: 1.8.0
|
mlly: 1.8.0
|
||||||
pathe: 1.1.2
|
pathe: 1.1.2
|
||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
vite: 5.4.20(@types/node@24.3.1)
|
vite: 5.4.21(@types/node@24.3.1)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/node'
|
- '@types/node'
|
||||||
- less
|
- less
|
||||||
@@ -1374,18 +1376,18 @@ snapshots:
|
|||||||
- supports-color
|
- supports-color
|
||||||
- terser
|
- terser
|
||||||
|
|
||||||
vite-tsconfig-paths@4.3.2(typescript@5.8.3)(vite@5.4.20(@types/node@24.3.1)):
|
vite-tsconfig-paths@4.3.2(typescript@5.8.3)(vite@5.4.21(@types/node@24.3.1)):
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.1
|
debug: 4.4.1
|
||||||
globrex: 0.1.2
|
globrex: 0.1.2
|
||||||
tsconfck: 3.1.6(typescript@5.8.3)
|
tsconfck: 3.1.6(typescript@5.8.3)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 5.4.20(@types/node@24.3.1)
|
vite: 5.4.21(@types/node@24.3.1)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
- typescript
|
- typescript
|
||||||
|
|
||||||
vite@5.4.20(@types/node@24.3.1):
|
vite@5.4.21(@types/node@24.3.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.25.9
|
esbuild: 0.25.9
|
||||||
postcss: 8.5.6
|
postcss: 8.5.6
|
||||||
@@ -1417,7 +1419,7 @@ snapshots:
|
|||||||
strip-literal: 1.3.0
|
strip-literal: 1.3.0
|
||||||
tinybench: 2.9.0
|
tinybench: 2.9.0
|
||||||
tinypool: 0.5.0
|
tinypool: 0.5.0
|
||||||
vite: 5.4.20(@types/node@24.3.1)
|
vite: 5.4.21(@types/node@24.3.1)
|
||||||
vite-node: 0.32.4(@types/node@24.3.1)
|
vite-node: 0.32.4(@types/node@24.3.1)
|
||||||
why-is-node-running: 2.3.0
|
why-is-node-running: 2.3.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
AUTH_API_PREFIX=""
|
AUTH_API_PREFIX=""
|
||||||
|
AUTH_ENCRYPTION_KEY="5181f67e2844e4b60d571fa346cac9c37fc00d1ff519212eae6cead138e639ba"
|
||||||
HASURA_GRAPHQL_DATABASE_URL="postgres://postgres:postgres@127.0.0.1:5432/local"
|
HASURA_GRAPHQL_DATABASE_URL="postgres://postgres:postgres@127.0.0.1:5432/local"
|
||||||
HASURA_GRAPHQL_JWT_SECRET='{"type":"HS256", "key":"5152fa850c02dc222631cca898ed1485821a70912a6e3649c49076912daa3b62182ba013315915d64f40cddfbb8b58eb5bd11ba225336a6af45bbae07ca873f3","issuer":"hasura-auth"}'
|
HASURA_GRAPHQL_JWT_SECRET='{"type":"HS256", "key":"5152fa850c02dc222631cca898ed1485821a70912a6e3649c49076912daa3b62182ba013315915d64f40cddfbb8b58eb5bd11ba225336a6af45bbae07ca873f3","issuer":"hasura-auth"}'
|
||||||
# HASURA_GRAPHQL_JWT_SECRET='{"type":"RS256", "key":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0M9zJVMJV8TgNPT9p737\nKR1XyWL9PSePXdcyk9aWcusG/m2OGsvuAgbMuDQx+Pns9PH9hd1kl53yfpTXOp3T\n13Uqox3IuHMlx8JyS+raqURSAew8/RkQ8nq+68XBBr9atDvVcSknS+jtZGH6Du1V\ntUy7Sz8VTVQuXDURF1Aa2wwNkRkC/wg5X0BXfN4Felh+mpK05PZbqJcRA5dbDlWk\n5nkdKbCG3urmtfF8brh6SlV7xBODJbqQws6E9WTclDQXWjmjcVNVSJE7OblZj1JB\nNGMN9rjUSS1kiRozhMtSlRv9MHAsz3e05MnvbyMWtoRpH8iLs0jmf8uucEBkMS/6\nBQIDAQAB\n-----END PUBLIC KEY-----","signing_key":"-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDQz3MlUwlXxOA0\n9P2nvfspHVfJYv09J49d1zKT1pZy6wb+bY4ay+4CBsy4NDH4+ez08f2F3WSXnfJ+\nlNc6ndPXdSqjHci4cyXHwnJL6tqpRFIB7Dz9GRDyer7rxcEGv1q0O9VxKSdL6O1k\nYfoO7VW1TLtLPxVNVC5cNREXUBrbDA2RGQL/CDlfQFd83gV6WH6akrTk9luolxED\nl1sOVaTmeR0psIbe6ua18XxuuHpKVXvEE4MlupDCzoT1ZNyUNBdaOaNxU1VIkTs5\nuVmPUkE0Yw32uNRJLWSJGjOEy1KVG/0wcCzPd7Tkye9vIxa2hGkfyIuzSOZ/y65w\nQGQxL/oFAgMBAAECggEBAKO3g1hoWpLuUbwzug2i7yG1V/cWHees9MNmzskLHrrL\ne5hQ3XI1Ik+EdU6X3faQPjFu6o/indQiitakbHwQ8t+jheKOn6m+3ohY9LSBVyAP\n6RyI1Oi8loUHqFnDmyxnK/7USu2GjsD9x+NEzoKVovWbS94bf+A5eH/jO5tDu0qy\nJMoe2jLx5IQQwLuvmQ+5ccZOUSQLG4/9Bw7g4xdroSvyVH27g9hqmEuY2orhcMm3\nlvlAx3PIH/kjKtpnP6MIBDhznlJ/VqAHhT/zC9xIwohyVGymoyDhdNSpn5N2QmWK\nKsneTdYdWz/oMB+HtcmvSoI4saEv1tlGEOTTINyBpwECgYEA+vrMFKhIoS3EbNiS\n5mSw/ejHl+60hsORGahPaYoXDfbDr2lyG58OfGu+l0qIe5SX4ueHo+ydhN70GR4l\nrtX9R+8uV9hb4B9e/hTZZnnAyFZrZSPfx4ZtPeyAlL+zhIGwxTy4BrbuxgynGict\nu+7XgbOYesDGRCvc4/1HKOgnf9kCgYEA1Py22UkY1iQQ4JNkfI1U6XqrydlMy1BG\nYSglI37UkVGUWG1hry+HCdhxHupBeUspZ/4vzKCLO1A1RlkCi9+TcOpY8UBqo1uq\nBaBPSlWD7T4oTOEPvANqT43SJ+RFkjtfVvDDtXBImO0+Nu57FmD6pMZJtvsxFkQB\nZKP6Mx3Q3A0CgYEAmGQJ4I0htIQmnXSPFceT1EgwUOdGxAEhLHQO6+VGBFuODAc5\nmt3kHNYLHq/J2UerRcIRkQ4NwuzhSBMPDG6wYKow+HPNrXM+6YXdTySkUsBuazXy\nHaNY112v4SHZLZ7Vp50rnCAdMTHjkLSzR0ZJol5bOkWs3R3I/MIAIC1+NlkCgYEA\n0kevP1er7cAt6Yub6lyfOOSkNuUTrKfU1JeOEz1lIRQqIiPcDdoeuNm41Yzyl45d\nkw6ioqTe0fCeqJW4reBO8Wxt48J1hlM5ydQ8dGd5mQGFSGHr5vR4QZMDqd710SpN\nNsj+cGQrSNDyW8mYPMACtiwPG1llXVZHCdXbcBw/2QECgYABLllfHVarmMwKTLWo\n8rRdEsIwcD/VxOxG4BxL6rZNQ4ADd8pL+9TohZeWp8wvlDGU7yB9wgyaD62Mhyog\nAGJt5Y/twAPTiVEi+0jVCXraLwPZpQFafw7p/x33eHkhwOTqlwlkRNlvrVk6A29I\nU0PVQZdMwEj/CPZVeCJ4DX63qQ==\n-----END PRIVATE KEY-----","issuer":"hasura-auth"}'
|
# HASURA_GRAPHQL_JWT_SECRET='{"type":"RS256", "key":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0M9zJVMJV8TgNPT9p737\nKR1XyWL9PSePXdcyk9aWcusG/m2OGsvuAgbMuDQx+Pns9PH9hd1kl53yfpTXOp3T\n13Uqox3IuHMlx8JyS+raqURSAew8/RkQ8nq+68XBBr9atDvVcSknS+jtZGH6Du1V\ntUy7Sz8VTVQuXDURF1Aa2wwNkRkC/wg5X0BXfN4Felh+mpK05PZbqJcRA5dbDlWk\n5nkdKbCG3urmtfF8brh6SlV7xBODJbqQws6E9WTclDQXWjmjcVNVSJE7OblZj1JB\nNGMN9rjUSS1kiRozhMtSlRv9MHAsz3e05MnvbyMWtoRpH8iLs0jmf8uucEBkMS/6\nBQIDAQAB\n-----END PUBLIC KEY-----","signing_key":"-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDQz3MlUwlXxOA0\n9P2nvfspHVfJYv09J49d1zKT1pZy6wb+bY4ay+4CBsy4NDH4+ez08f2F3WSXnfJ+\nlNc6ndPXdSqjHci4cyXHwnJL6tqpRFIB7Dz9GRDyer7rxcEGv1q0O9VxKSdL6O1k\nYfoO7VW1TLtLPxVNVC5cNREXUBrbDA2RGQL/CDlfQFd83gV6WH6akrTk9luolxED\nl1sOVaTmeR0psIbe6ua18XxuuHpKVXvEE4MlupDCzoT1ZNyUNBdaOaNxU1VIkTs5\nuVmPUkE0Yw32uNRJLWSJGjOEy1KVG/0wcCzPd7Tkye9vIxa2hGkfyIuzSOZ/y65w\nQGQxL/oFAgMBAAECggEBAKO3g1hoWpLuUbwzug2i7yG1V/cWHees9MNmzskLHrrL\ne5hQ3XI1Ik+EdU6X3faQPjFu6o/indQiitakbHwQ8t+jheKOn6m+3ohY9LSBVyAP\n6RyI1Oi8loUHqFnDmyxnK/7USu2GjsD9x+NEzoKVovWbS94bf+A5eH/jO5tDu0qy\nJMoe2jLx5IQQwLuvmQ+5ccZOUSQLG4/9Bw7g4xdroSvyVH27g9hqmEuY2orhcMm3\nlvlAx3PIH/kjKtpnP6MIBDhznlJ/VqAHhT/zC9xIwohyVGymoyDhdNSpn5N2QmWK\nKsneTdYdWz/oMB+HtcmvSoI4saEv1tlGEOTTINyBpwECgYEA+vrMFKhIoS3EbNiS\n5mSw/ejHl+60hsORGahPaYoXDfbDr2lyG58OfGu+l0qIe5SX4ueHo+ydhN70GR4l\nrtX9R+8uV9hb4B9e/hTZZnnAyFZrZSPfx4ZtPeyAlL+zhIGwxTy4BrbuxgynGict\nu+7XgbOYesDGRCvc4/1HKOgnf9kCgYEA1Py22UkY1iQQ4JNkfI1U6XqrydlMy1BG\nYSglI37UkVGUWG1hry+HCdhxHupBeUspZ/4vzKCLO1A1RlkCi9+TcOpY8UBqo1uq\nBaBPSlWD7T4oTOEPvANqT43SJ+RFkjtfVvDDtXBImO0+Nu57FmD6pMZJtvsxFkQB\nZKP6Mx3Q3A0CgYEAmGQJ4I0htIQmnXSPFceT1EgwUOdGxAEhLHQO6+VGBFuODAc5\nmt3kHNYLHq/J2UerRcIRkQ4NwuzhSBMPDG6wYKow+HPNrXM+6YXdTySkUsBuazXy\nHaNY112v4SHZLZ7Vp50rnCAdMTHjkLSzR0ZJol5bOkWs3R3I/MIAIC1+NlkCgYEA\n0kevP1er7cAt6Yub6lyfOOSkNuUTrKfU1JeOEz1lIRQqIiPcDdoeuNm41Yzyl45d\nkw6ioqTe0fCeqJW4reBO8Wxt48J1hlM5ydQ8dGd5mQGFSGHr5vR4QZMDqd710SpN\nNsj+cGQrSNDyW8mYPMACtiwPG1llXVZHCdXbcBw/2QECgYABLllfHVarmMwKTLWo\n8rRdEsIwcD/VxOxG4BxL6rZNQ4ADd8pL+9TohZeWp8wvlDGU7yB9wgyaD62Mhyog\nAGJt5Y/twAPTiVEi+0jVCXraLwPZpQFafw7p/x33eHkhwOTqlwlkRNlvrVk6A29I\nU0PVQZdMwEj/CPZVeCJ4DX63qQ==\n-----END PRIVATE KEY-----","issuer":"hasura-auth"}'
|
||||||
|
|||||||
@@ -2,6 +2,23 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [auth@0.42.4] - 2025-10-20
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- *(auth)* Apply relationships on new projects (#3617)
|
||||||
|
|
||||||
|
## [auth@0.42.3] - 2025-10-20
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- *(auth)* Always apply expected metadata (#3616)
|
||||||
|
|
||||||
|
|
||||||
|
### ⚙️ Miscellaneous Tasks
|
||||||
|
|
||||||
|
- *(storage)* Migrate to urfave and slog libraries (#3606)
|
||||||
|
|
||||||
## [auth@0.42.2] - 2025-10-13
|
## [auth@0.42.2] - 2025-10-13
|
||||||
|
|
||||||
### ⚙️ Miscellaneous Tasks
|
### ⚙️ Miscellaneous Tasks
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ services:
|
|||||||
HASURA_GRAPHQL_JWT_SECRET: '{"type":"HS256", "key":"5152fa850c02dc222631cca898ed1485821a70912a6e3649c49076912daa3b62182ba013315915d64f40cddfbb8b58eb5bd11ba225336a6af45bbae07ca873f3","issuer":"hasura-auth"}'
|
HASURA_GRAPHQL_JWT_SECRET: '{"type":"HS256", "key":"5152fa850c02dc222631cca898ed1485821a70912a6e3649c49076912daa3b62182ba013315915d64f40cddfbb8b58eb5bd11ba225336a6af45bbae07ca873f3","issuer":"hasura-auth"}'
|
||||||
HASURA_GRAPHQL_ADMIN_SECRET: nhost-admin-secret
|
HASURA_GRAPHQL_ADMIN_SECRET: nhost-admin-secret
|
||||||
HASURA_GRAPHQL_GRAPHQL_URL: http://graphql:8080/v1/graphql
|
HASURA_GRAPHQL_GRAPHQL_URL: http://graphql:8080/v1/graphql
|
||||||
|
AUTH_ENCRYPTION_KEY: 5181f67e2844e4b60d571fa346cac9c37fc00d1ff519212eae6cead138e639ba
|
||||||
AUTH_PORT: 4000
|
AUTH_PORT: 4000
|
||||||
AUTH_SERVER_URL: http://127.0.0.2:4000
|
AUTH_SERVER_URL: http://127.0.0.2:4000
|
||||||
AUTH_USER_DEFAULT_ALLOWED_ROLES: 'me,user,editor'
|
AUTH_USER_DEFAULT_ALLOWED_ROLES: 'me,user,editor'
|
||||||
|
|||||||
@@ -1308,7 +1308,7 @@ components:
|
|||||||
BearerAuthElevated:
|
BearerAuthElevated:
|
||||||
type: http
|
type: http
|
||||||
scheme: bearer
|
scheme: bearer
|
||||||
description: "Bearer authentication that requires elevated permissions. Used for sensitive operations that may require additional security measures such as recent authentication. For details see https://docs.nhost.io/guides/auth/elevated-permissions"
|
description: "Bearer authentication that requires elevated permissions. Used for sensitive operations that may require additional security measures such as recent authentication. For details see https://docs.nhost.io/products/auth/elevated-permissions"
|
||||||
|
|
||||||
schemas:
|
schemas:
|
||||||
AttestationFormat:
|
AttestationFormat:
|
||||||
|
|||||||
@@ -3643,84 +3643,84 @@ var swaggerSpec = []string{
|
|||||||
"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",
|
||||||
"AP//J2Dqrmj4AAA=",
|
"fwAAAP//NPNLB2r4AAA=",
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSwagger returns the content of the embedded swagger specification file
|
// GetSwagger returns the content of the embedded swagger specification file
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"log/slog"
|
"log/slog"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
crypto "github.com/nhost/nhost/services/auth/go/cryto"
|
||||||
"github.com/nhost/nhost/services/auth/go/migrations"
|
"github.com/nhost/nhost/services/auth/go/migrations"
|
||||||
"github.com/nhost/nhost/services/auth/go/sql"
|
"github.com/nhost/nhost/services/auth/go/sql"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
@@ -48,7 +49,11 @@ func insertRoles(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func applyMigrations(
|
func applyMigrations(
|
||||||
ctx context.Context, cmd *cli.Command, db *sql.Queries, logger *slog.Logger,
|
ctx context.Context,
|
||||||
|
cmd *cli.Command,
|
||||||
|
db *sql.Queries,
|
||||||
|
encrypter *crypto.Encrypter,
|
||||||
|
logger *slog.Logger,
|
||||||
) error {
|
) error {
|
||||||
postgresURL := cmd.String(flagPostgresMigrationsConnection)
|
postgresURL := cmd.String(flagPostgresMigrationsConnection)
|
||||||
if postgresURL == "" {
|
if postgresURL == "" {
|
||||||
@@ -71,5 +76,15 @@ func applyMigrations(
|
|||||||
return fmt.Errorf("failed to apply hasura metadata: %w", err)
|
return fmt.Errorf("failed to apply hasura metadata: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := migrations.EncryptTOTPSecrets(ctx, db, encrypter, logger); err != nil {
|
||||||
|
logger.ErrorContext(
|
||||||
|
ctx,
|
||||||
|
"failed to encrypt TOTP secrets",
|
||||||
|
slog.String("error", err.Error()),
|
||||||
|
)
|
||||||
|
|
||||||
|
return fmt.Errorf("failed to encrypt TOTP secrets: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return insertRoles(ctx, cmd, db, logger)
|
return insertRoles(ctx, cmd, db, logger)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/nhost/nhost/services/auth/docs"
|
"github.com/nhost/nhost/services/auth/docs"
|
||||||
"github.com/nhost/nhost/services/auth/go/api"
|
"github.com/nhost/nhost/services/auth/go/api"
|
||||||
"github.com/nhost/nhost/services/auth/go/controller"
|
"github.com/nhost/nhost/services/auth/go/controller"
|
||||||
|
crypto "github.com/nhost/nhost/services/auth/go/cryto"
|
||||||
"github.com/nhost/nhost/services/auth/go/hibp"
|
"github.com/nhost/nhost/services/auth/go/hibp"
|
||||||
"github.com/nhost/nhost/services/auth/go/middleware"
|
"github.com/nhost/nhost/services/auth/go/middleware"
|
||||||
"github.com/nhost/nhost/services/auth/go/middleware/ratelimit"
|
"github.com/nhost/nhost/services/auth/go/middleware/ratelimit"
|
||||||
@@ -29,6 +30,7 @@ const (
|
|||||||
flagPort = "port"
|
flagPort = "port"
|
||||||
flagDebug = "debug"
|
flagDebug = "debug"
|
||||||
flagLogFormatTEXT = "log-format-text"
|
flagLogFormatTEXT = "log-format-text"
|
||||||
|
flagEncryptionKey = "encryption-key"
|
||||||
flagTrustedProxies = "trusted-proxies"
|
flagTrustedProxies = "trusted-proxies"
|
||||||
flagPostgresConnection = "postgres"
|
flagPostgresConnection = "postgres"
|
||||||
flagPostgresMigrationsConnection = "postgres-migrations"
|
flagPostgresMigrationsConnection = "postgres-migrations"
|
||||||
@@ -211,6 +213,13 @@ func CommandServe() *cli.Command { //nolint:funlen,maintidx
|
|||||||
Category: "general",
|
Category: "general",
|
||||||
Sources: cli.EnvVars("AUTH_LOG_FORMAT_TEXT"),
|
Sources: cli.EnvVars("AUTH_LOG_FORMAT_TEXT"),
|
||||||
},
|
},
|
||||||
|
&cli.StringFlag{ //nolint: exhaustruct
|
||||||
|
Name: flagEncryptionKey,
|
||||||
|
Usage: "32 bytes encryption key used to encrypt sensitive data. Must be a hex-encoded string",
|
||||||
|
Category: "security",
|
||||||
|
Sources: cli.EnvVars("AUTH_ENCRYPTION_KEY"),
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
&cli.StringFlag{ //nolint: exhaustruct
|
&cli.StringFlag{ //nolint: exhaustruct
|
||||||
Name: flagPostgresConnection,
|
Name: flagPostgresConnection,
|
||||||
Usage: "PostgreSQL connection URI: https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING",
|
Usage: "PostgreSQL connection URI: https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING",
|
||||||
@@ -1288,7 +1297,11 @@ func getDependencies( //nolint:ireturn
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getGoServer( //nolint:funlen
|
func getGoServer( //nolint:funlen
|
||||||
ctx context.Context, cmd *cli.Command, db *sql.Queries, logger *slog.Logger,
|
ctx context.Context,
|
||||||
|
cmd *cli.Command,
|
||||||
|
db *sql.Queries,
|
||||||
|
encrypter *crypto.Encrypter,
|
||||||
|
logger *slog.Logger,
|
||||||
) (*http.Server, error) {
|
) (*http.Server, error) {
|
||||||
router := gin.New()
|
router := gin.New()
|
||||||
|
|
||||||
@@ -1347,6 +1360,7 @@ func getGoServer( //nolint:funlen
|
|||||||
oauthProviders,
|
oauthProviders,
|
||||||
idTokenValidator,
|
idTokenValidator,
|
||||||
controller.NewTotp(cmd.String(flagMfaTotpIssuer), time.Now),
|
controller.NewTotp(cmd.String(flagMfaTotpIssuer), time.Now),
|
||||||
|
encrypter,
|
||||||
cmd.Root().Version,
|
cmd.Root().Version,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1410,12 +1424,17 @@ func serve(ctx context.Context, cmd *cli.Command) error {
|
|||||||
}
|
}
|
||||||
defer pool.Close()
|
defer pool.Close()
|
||||||
|
|
||||||
|
encrypter, err := crypto.NewEncrypterFromString(cmd.String(flagEncryptionKey))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("problem creating encrypter: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
db := sql.New(pool)
|
db := sql.New(pool)
|
||||||
if err := applyMigrations(servCtx, cmd, db, logger); err != nil {
|
if err := applyMigrations(servCtx, cmd, db, encrypter, logger); err != nil {
|
||||||
return fmt.Errorf("failed to apply migrations: %w", err)
|
return fmt.Errorf("failed to apply migrations: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
server, err := getGoServer(ctx, cmd, db, logger)
|
server, err := getGoServer(ctx, cmd, db, encrypter, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create server: %w", err)
|
return fmt.Errorf("failed to create server: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,16 +32,22 @@ func (ctrl *Controller) ChangeUserMfa( //nolint:ireturn
|
|||||||
accountName = user.ID.String()
|
accountName = user.ID.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
secret, imgBase64, err := ctrl.totp.Generate(accountName)
|
plainSecret, imgBase64, err := ctrl.totp.Generate(accountName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.ErrorContext(ctx, "failed to generate TOTP: %v", logError(err))
|
logger.ErrorContext(ctx, "failed to generate TOTP: %v", logError(err))
|
||||||
return ctrl.sendError(ErrInternalServerError), nil
|
return ctrl.sendError(ErrInternalServerError), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
secret, err := ctrl.encrypter.Encrypt([]byte(plainSecret))
|
||||||
|
if err != nil {
|
||||||
|
logger.ErrorContext(ctx, "failed to encrypt TOTP secret: %v", logError(err))
|
||||||
|
return ctrl.sendError(ErrInternalServerError), nil
|
||||||
|
}
|
||||||
|
|
||||||
if err := ctrl.wf.db.UpdateUserTotpSecret(
|
if err := ctrl.wf.db.UpdateUserTotpSecret(
|
||||||
ctx, sql.UpdateUserTotpSecretParams{
|
ctx, sql.UpdateUserTotpSecretParams{
|
||||||
ID: user.ID,
|
ID: user.ID,
|
||||||
TotpSecret: sql.Text(secret),
|
TotpSecret: sql.Text(string(secret)),
|
||||||
},
|
},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
logger.ErrorContext(ctx, "failed to update TOTP secret: %v", logError(err))
|
logger.ErrorContext(ctx, "failed to update TOTP secret: %v", logError(err))
|
||||||
@@ -50,6 +56,6 @@ func (ctrl *Controller) ChangeUserMfa( //nolint:ireturn
|
|||||||
|
|
||||||
return api.ChangeUserMfa200JSONResponse{
|
return api.ChangeUserMfa200JSONResponse{
|
||||||
ImageUrl: "data:image/png;base64," + imgBase64,
|
ImageUrl: "data:image/png;base64," + imgBase64,
|
||||||
TotpSecret: secret,
|
TotpSecret: plainSecret,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,10 +13,19 @@ import (
|
|||||||
"github.com/nhost/nhost/services/auth/go/controller"
|
"github.com/nhost/nhost/services/auth/go/controller"
|
||||||
"github.com/nhost/nhost/services/auth/go/controller/mock"
|
"github.com/nhost/nhost/services/auth/go/controller/mock"
|
||||||
"github.com/nhost/nhost/services/auth/go/sql"
|
"github.com/nhost/nhost/services/auth/go/sql"
|
||||||
"github.com/nhost/nhost/services/auth/go/testhelpers"
|
|
||||||
"go.uber.org/mock/gomock"
|
"go.uber.org/mock/gomock"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type fakeEncrypter struct{}
|
||||||
|
|
||||||
|
func (e *fakeEncrypter) Encrypt(_ []byte) ([]byte, error) {
|
||||||
|
return []byte("encrypted-data"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *fakeEncrypter) Decrypt(_ []byte) ([]byte, error) {
|
||||||
|
return []byte("decrypted-data"), nil
|
||||||
|
}
|
||||||
|
|
||||||
func ImageURLComparer() cmp.Option {
|
func ImageURLComparer() cmp.Option {
|
||||||
return cmp.FilterPath(func(p cmp.Path) bool {
|
return cmp.FilterPath(func(p cmp.Path) bool {
|
||||||
if last := p.Last(); last != nil {
|
if last := p.Last(); last != nil {
|
||||||
@@ -78,15 +87,9 @@ func TestGetMfaTotpGenerate(t *testing.T) {
|
|||||||
gomock.Any(),
|
gomock.Any(),
|
||||||
cmpDBParams(
|
cmpDBParams(
|
||||||
sql.UpdateUserTotpSecretParams{
|
sql.UpdateUserTotpSecretParams{
|
||||||
ID: userID,
|
ID: userID,
|
||||||
TotpSecret: sql.Text(
|
TotpSecret: sql.Text("encrypted-data"),
|
||||||
"FEWCQAIILM6UOYZCPFYRAPAUCIFUUUK3JUZXWKJIN4ORQNK4EQCQ",
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
testhelpers.FilterPathLast(
|
|
||||||
[]string{".TotpSecret", "text()"},
|
|
||||||
cmp.Comparer(cmpTicket),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
).Return(nil)
|
).Return(nil)
|
||||||
|
|
||||||
@@ -97,9 +100,11 @@ func TestGetMfaTotpGenerate(t *testing.T) {
|
|||||||
ImageUrl: "data:image/png;base64,",
|
ImageUrl: "data:image/png;base64,",
|
||||||
TotpSecret: "AIRVH6M4V422LZI6IRBN5SCEO6BWVIW3G6PLKKTENHMGZYRALPOQ",
|
TotpSecret: "AIRVH6M4V422LZI6IRBN5SCEO6BWVIW3G6PLKKTENHMGZYRALPOQ",
|
||||||
},
|
},
|
||||||
expectedJWT: nil,
|
expectedJWT: nil,
|
||||||
jwtTokenFn: jwtTokenFn,
|
jwtTokenFn: jwtTokenFn,
|
||||||
getControllerOpts: nil,
|
getControllerOpts: []getControllerOptsFunc{
|
||||||
|
withEncrypter(&fakeEncrypter{}),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -130,8 +130,14 @@ type DBClient interface { //nolint:interfacebloat
|
|||||||
) ([]sql.RefreshTokenAndGetUserRolesRow, error)
|
) ([]sql.RefreshTokenAndGetUserRolesRow, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Encrypter interface {
|
||||||
|
Encrypt(plainText []byte) ([]byte, error)
|
||||||
|
Decrypt(cipherText []byte) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
type Controller struct {
|
type Controller struct {
|
||||||
totp *Totp
|
totp *Totp
|
||||||
|
encrypter Encrypter
|
||||||
idTokenValidator *oidc.IDTokenValidatorProviders
|
idTokenValidator *oidc.IDTokenValidatorProviders
|
||||||
wf *Workflows
|
wf *Workflows
|
||||||
config Config
|
config Config
|
||||||
@@ -150,6 +156,7 @@ func New(
|
|||||||
providers providers.Map,
|
providers providers.Map,
|
||||||
idTokenValidator *oidc.IDTokenValidatorProviders,
|
idTokenValidator *oidc.IDTokenValidatorProviders,
|
||||||
totp *Totp,
|
totp *Totp,
|
||||||
|
encrypter Encrypter,
|
||||||
version string,
|
version string,
|
||||||
) (*Controller, error) {
|
) (*Controller, error) {
|
||||||
validator, err := NewWorkflows(
|
validator, err := NewWorkflows(
|
||||||
@@ -182,6 +189,7 @@ func New(
|
|||||||
Webauthn: wa,
|
Webauthn: wa,
|
||||||
idTokenValidator: idTokenValidator,
|
idTokenValidator: idTokenValidator,
|
||||||
totp: totp,
|
totp: totp,
|
||||||
|
encrypter: encrypter,
|
||||||
version: version,
|
version: version,
|
||||||
Providers: providers,
|
Providers: providers,
|
||||||
}, nil
|
}, nil
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/nhost/nhost/services/auth/go/api"
|
"github.com/nhost/nhost/services/auth/go/api"
|
||||||
"github.com/nhost/nhost/services/auth/go/controller"
|
"github.com/nhost/nhost/services/auth/go/controller"
|
||||||
"github.com/nhost/nhost/services/auth/go/controller/mock"
|
"github.com/nhost/nhost/services/auth/go/controller/mock"
|
||||||
|
crypto "github.com/nhost/nhost/services/auth/go/cryto"
|
||||||
"github.com/nhost/nhost/services/auth/go/oidc"
|
"github.com/nhost/nhost/services/auth/go/oidc"
|
||||||
"github.com/nhost/nhost/services/auth/go/providers"
|
"github.com/nhost/nhost/services/auth/go/providers"
|
||||||
"github.com/nhost/nhost/services/auth/go/testhelpers"
|
"github.com/nhost/nhost/services/auth/go/testhelpers"
|
||||||
@@ -180,6 +181,7 @@ type getControllerOpts struct {
|
|||||||
hibp func(*gomock.Controller) *mock.MockHIBPClient
|
hibp func(*gomock.Controller) *mock.MockHIBPClient
|
||||||
idTokenValidatorProviders func(t *testing.T) *oidc.IDTokenValidatorProviders
|
idTokenValidatorProviders func(t *testing.T) *oidc.IDTokenValidatorProviders
|
||||||
totp *controller.Totp
|
totp *controller.Totp
|
||||||
|
encrypter controller.Encrypter
|
||||||
}
|
}
|
||||||
|
|
||||||
type getControllerOptsFunc func(*getControllerOpts)
|
type getControllerOptsFunc func(*getControllerOpts)
|
||||||
@@ -222,7 +224,13 @@ func withTotp(totp *controller.Totp) getControllerOptsFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getController(
|
func withEncrypter(encrypter controller.Encrypter) getControllerOptsFunc {
|
||||||
|
return func(o *getControllerOpts) {
|
||||||
|
o.encrypter = encrypter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getController( //nolint:cyclop
|
||||||
t *testing.T,
|
t *testing.T,
|
||||||
ctrl *gomock.Controller,
|
ctrl *gomock.Controller,
|
||||||
configFn func() *controller.Config,
|
configFn func() *controller.Config,
|
||||||
@@ -278,6 +286,17 @@ func getController(
|
|||||||
controllerOpts.totp = controller.NewTotp("auth", time.Now)
|
controllerOpts.totp = controller.NewTotp("auth", time.Now)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if controllerOpts.encrypter == nil {
|
||||||
|
encrypter, err := crypto.NewEncrypterFromString(
|
||||||
|
"41e7109ea7cfff9e4100d29bbd58bacab0258d0fc4c0495746ed0cf166650f9d",
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create encrypter: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
controllerOpts.encrypter = encrypter
|
||||||
|
}
|
||||||
|
|
||||||
c, err := controller.New(
|
c, err := controller.New(
|
||||||
db(ctrl),
|
db(ctrl),
|
||||||
config,
|
config,
|
||||||
@@ -295,6 +314,7 @@ func getController(
|
|||||||
},
|
},
|
||||||
idTokenValidator,
|
idTokenValidator,
|
||||||
controllerOpts.totp,
|
controllerOpts.totp,
|
||||||
|
controllerOpts.encrypter,
|
||||||
"dev",
|
"dev",
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1124,3 +1124,57 @@ func (mr *MockDBClientMockRecorder) UpdateUserVerifyEmail(ctx, id any) *gomock.C
|
|||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserVerifyEmail", reflect.TypeOf((*MockDBClient)(nil).UpdateUserVerifyEmail), ctx, id)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserVerifyEmail", reflect.TypeOf((*MockDBClient)(nil).UpdateUserVerifyEmail), ctx, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MockEncrypter is a mock of Encrypter interface.
|
||||||
|
type MockEncrypter struct {
|
||||||
|
ctrl *gomock.Controller
|
||||||
|
recorder *MockEncrypterMockRecorder
|
||||||
|
isgomock struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockEncrypterMockRecorder is the mock recorder for MockEncrypter.
|
||||||
|
type MockEncrypterMockRecorder struct {
|
||||||
|
mock *MockEncrypter
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMockEncrypter creates a new mock instance.
|
||||||
|
func NewMockEncrypter(ctrl *gomock.Controller) *MockEncrypter {
|
||||||
|
mock := &MockEncrypter{ctrl: ctrl}
|
||||||
|
mock.recorder = &MockEncrypterMockRecorder{mock}
|
||||||
|
return mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||||
|
func (m *MockEncrypter) EXPECT() *MockEncrypterMockRecorder {
|
||||||
|
return m.recorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt mocks base method.
|
||||||
|
func (m *MockEncrypter) Decrypt(cipherText []byte) ([]byte, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "Decrypt", cipherText)
|
||||||
|
ret0, _ := ret[0].([]byte)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt indicates an expected call of Decrypt.
|
||||||
|
func (mr *MockEncrypterMockRecorder) Decrypt(cipherText any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Decrypt", reflect.TypeOf((*MockEncrypter)(nil).Decrypt), cipherText)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt mocks base method.
|
||||||
|
func (m *MockEncrypter) Encrypt(plainText []byte) ([]byte, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "Encrypt", plainText)
|
||||||
|
ret0, _ := ret[0].([]byte)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt indicates an expected call of Encrypt.
|
||||||
|
func (mr *MockEncrypterMockRecorder) Encrypt(plainText any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Encrypt", reflect.TypeOf((*MockEncrypter)(nil).Encrypt), plainText)
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,7 +28,13 @@ func (ctrl *Controller) postUserMfaDeactivate( //nolint:ireturn
|
|||||||
return ctrl.sendError(ErrNoTotpSecret)
|
return ctrl.sendError(ErrNoTotpSecret)
|
||||||
}
|
}
|
||||||
|
|
||||||
valid := ctrl.totp.Validate(req.Body.Code, user.TotpSecret.String)
|
totpSecret, err := ctrl.encrypter.Decrypt([]byte(user.TotpSecret.String))
|
||||||
|
if err != nil {
|
||||||
|
logger.ErrorContext(ctx, "failed to decrypt totp secret", logError(err))
|
||||||
|
return ctrl.sendError(ErrInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
valid := ctrl.totp.Validate(req.Body.Code, string(totpSecret))
|
||||||
if !valid {
|
if !valid {
|
||||||
logger.WarnContext(ctx, "invalid totp")
|
logger.WarnContext(ctx, "invalid totp")
|
||||||
return ctrl.sendError(ErrInvalidTotp)
|
return ctrl.sendError(ErrInvalidTotp)
|
||||||
@@ -65,7 +71,13 @@ func (ctrl *Controller) postUserMfaActivate( //nolint:ireturn
|
|||||||
return ctrl.sendError(ErrNoTotpSecret)
|
return ctrl.sendError(ErrNoTotpSecret)
|
||||||
}
|
}
|
||||||
|
|
||||||
valid := ctrl.totp.Validate(req.Body.Code, user.TotpSecret.String)
|
totpSecret, err := ctrl.encrypter.Decrypt([]byte(user.TotpSecret.String))
|
||||||
|
if err != nil {
|
||||||
|
logger.ErrorContext(ctx, "failed to decrypt totp secret", logError(err))
|
||||||
|
return ctrl.sendError(ErrInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
valid := ctrl.totp.Validate(req.Body.Code, string(totpSecret))
|
||||||
if !valid {
|
if !valid {
|
||||||
logger.WarnContext(ctx, "invalid totp")
|
logger.WarnContext(ctx, "invalid totp")
|
||||||
return ctrl.sendError(ErrInvalidTotp)
|
return ctrl.sendError(ErrInvalidTotp)
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ func TestVerifyChangeUserMfa(t *testing.T) { //nolint:maintidx
|
|||||||
).Return(sql.AuthUser{ //nolint:exhaustruct
|
).Return(sql.AuthUser{ //nolint:exhaustruct
|
||||||
ID: userID,
|
ID: userID,
|
||||||
Email: sql.Text("user@acme.local"),
|
Email: sql.Text("user@acme.local"),
|
||||||
TotpSecret: sql.Text("FEWCQAIILM6UOYZCPFYRAPAUCIFUUUK3JUZXWKJIN4ORQNK4EQCQ"),
|
TotpSecret: sql.Text(encryptedTotpSecret),
|
||||||
ActiveMfaType: pgtype.Text{}, //nolint:exhaustruct
|
ActiveMfaType: pgtype.Text{}, //nolint:exhaustruct
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ func TestVerifyChangeUserMfa(t *testing.T) { //nolint:maintidx
|
|||||||
).Return(sql.AuthUser{ //nolint:exhaustruct
|
).Return(sql.AuthUser{ //nolint:exhaustruct
|
||||||
ID: userID,
|
ID: userID,
|
||||||
Email: sql.Text("user@acme.local"),
|
Email: sql.Text("user@acme.local"),
|
||||||
TotpSecret: sql.Text("FEWCQAIILM6UOYZCPFYRAPAUCIFUUUK3JUZXWKJIN4ORQNK4EQCQ"),
|
TotpSecret: sql.Text(encryptedTotpSecret),
|
||||||
ActiveMfaType: sql.Text("totp"),
|
ActiveMfaType: sql.Text("totp"),
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
||||||
@@ -140,7 +140,7 @@ func TestVerifyChangeUserMfa(t *testing.T) { //nolint:maintidx
|
|||||||
).Return(sql.AuthUser{ //nolint:exhaustruct
|
).Return(sql.AuthUser{ //nolint:exhaustruct
|
||||||
ID: userID,
|
ID: userID,
|
||||||
Email: sql.Text("user@acme.local"),
|
Email: sql.Text("user@acme.local"),
|
||||||
TotpSecret: sql.Text("FEWCQAIILM6UOYZCPFYRAPAUCIFUUUK3JUZXWKJIN4ORQNK4EQCQ"),
|
TotpSecret: sql.Text(encryptedTotpSecret),
|
||||||
ActiveMfaType: pgtype.Text{}, //nolint:exhaustruct
|
ActiveMfaType: pgtype.Text{}, //nolint:exhaustruct
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
||||||
@@ -179,7 +179,7 @@ func TestVerifyChangeUserMfa(t *testing.T) { //nolint:maintidx
|
|||||||
).Return(sql.AuthUser{ //nolint:exhaustruct
|
).Return(sql.AuthUser{ //nolint:exhaustruct
|
||||||
ID: userID,
|
ID: userID,
|
||||||
Email: sql.Text("user@acme.local"),
|
Email: sql.Text("user@acme.local"),
|
||||||
TotpSecret: sql.Text("FEWCQAIILM6UOYZCPFYRAPAUCIFUUUK3JUZXWKJIN4ORQNK4EQCQ"),
|
TotpSecret: sql.Text(encryptedTotpSecret),
|
||||||
ActiveMfaType: sql.Text("totp"),
|
ActiveMfaType: sql.Text("totp"),
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
||||||
@@ -261,7 +261,7 @@ func TestVerifyChangeUserMfa(t *testing.T) { //nolint:maintidx
|
|||||||
).Return(sql.AuthUser{ //nolint:exhaustruct
|
).Return(sql.AuthUser{ //nolint:exhaustruct
|
||||||
ID: userID,
|
ID: userID,
|
||||||
Email: sql.Text("user@acme.local"),
|
Email: sql.Text("user@acme.local"),
|
||||||
TotpSecret: sql.Text("FEWCQAIILM6UOYZCPFYRAPAUCIFUUUK3JUZXWKJIN4ORQNK4EQCQ"),
|
TotpSecret: sql.Text(encryptedTotpSecret),
|
||||||
ActiveMfaType: sql.Text("totp"),
|
ActiveMfaType: sql.Text("totp"),
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,13 @@ func (ctrl *Controller) VerifySignInMfaTotp( //nolint:ireturn
|
|||||||
return ctrl.sendError(ErrNoTotpSecret), nil
|
return ctrl.sendError(ErrNoTotpSecret), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
valid := ctrl.totp.Validate(req.Body.Otp, user.TotpSecret.String)
|
totpSecret, err := ctrl.encrypter.Decrypt([]byte(user.TotpSecret.String))
|
||||||
|
if err != nil {
|
||||||
|
logger.ErrorContext(ctx, "failed to decrypt totp secret", logError(err))
|
||||||
|
return ctrl.sendError(ErrInternalServerError), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
valid := ctrl.totp.Validate(req.Body.Otp, string(totpSecret))
|
||||||
if !valid {
|
if !valid {
|
||||||
logger.WarnContext(ctx, "invalid totp")
|
logger.WarnContext(ctx, "invalid totp")
|
||||||
return ctrl.sendError(ErrInvalidTotp), nil
|
return ctrl.sendError(ErrInvalidTotp), nil
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ import (
|
|||||||
"go.uber.org/mock/gomock"
|
"go.uber.org/mock/gomock"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const encryptedTotpSecret = "fcceaa61a188729ca5e57108030cd5fde120365a986d3f4e1af1fafa598e8e99092128318cfb8fc1facbb870cbd2c90c5714b2914170bd69c868e906576f2a516da9e48c4237d87432342b6cf45392a2" //nolint:lll,gosec
|
||||||
|
|
||||||
func fakeNow(t time.Time) func() time.Time {
|
func fakeNow(t time.Time) func() time.Time {
|
||||||
return func() time.Time {
|
return func() time.Time {
|
||||||
return t
|
return t
|
||||||
@@ -40,7 +42,7 @@ func getUserSigninMfaTotp(userID uuid.UUID) sql.AuthUser {
|
|||||||
"$2a$10$pyv7eu9ioQcFnLSz7u/enex22P3ORdh6z6116Vj5a3vSjo0oxFa1u",
|
"$2a$10$pyv7eu9ioQcFnLSz7u/enex22P3ORdh6z6116Vj5a3vSjo0oxFa1u",
|
||||||
),
|
),
|
||||||
EmailVerified: true,
|
EmailVerified: true,
|
||||||
TotpSecret: sql.Text("FEWCQAIILM6UOYZCPFYRAPAUCIFUUUK3JUZXWKJIN4ORQNK4EQCQ"),
|
TotpSecret: sql.Text(encryptedTotpSecret),
|
||||||
ActiveMfaType: sql.Text("totp"),
|
ActiveMfaType: sql.Text("totp"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
117
services/auth/go/cryto/crypto.go
Normal file
117
services/auth/go/cryto/crypto.go
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrCiphertextTooShort = errors.New("ciphertext too short")
|
||||||
|
ErrDecryptionFailed = errors.New("decryption failed")
|
||||||
|
ErrWrongKeySize = errors.New(
|
||||||
|
"key must be 16, 24, or 32 bytes (AES-128, AES-192, or AES-256)",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
type Encrypter struct {
|
||||||
|
aead cipher.AEAD
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEncrypter creates a new encrypter using AES-GCM (AEAD mode).
|
||||||
|
func NewEncrypter(key []byte) (*Encrypter, error) {
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create AES cipher: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
aead, err := cipher.NewGCM(block)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create GCM: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Encrypter{
|
||||||
|
aead: aead,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEncrypterFromString creates a new encrypter from a hex string key.
|
||||||
|
func NewEncrypterFromString(hexKey string) (*Encrypter, error) {
|
||||||
|
key, err := KeyFromString(hexKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewEncrypter(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt encrypts the plaintext using AES-GCM
|
||||||
|
// The result includes the nonce and authentication tag.
|
||||||
|
func (enc *Encrypter) Encrypt(plaintext []byte) ([]byte, error) {
|
||||||
|
nonce := make([]byte, enc.aead.NonceSize())
|
||||||
|
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to generate nonce: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ciphertext := enc.aead.Seal(nonce, nonce, plaintext, nil)
|
||||||
|
|
||||||
|
encoded := make([]byte, hex.EncodedLen(len(ciphertext)))
|
||||||
|
hex.Encode(encoded, ciphertext)
|
||||||
|
|
||||||
|
return encoded, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt decrypts the ciphertext using AES-GCM
|
||||||
|
// Automatically verifies authentication tag.
|
||||||
|
func (enc *Encrypter) Decrypt(ciphertext []byte) ([]byte, error) {
|
||||||
|
decoded := make([]byte, hex.DecodedLen(len(ciphertext)))
|
||||||
|
|
||||||
|
_, err := hex.Decode(decoded, ciphertext)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode hex string: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(decoded) < enc.aead.NonceSize() {
|
||||||
|
return nil, ErrCiphertextTooShort
|
||||||
|
}
|
||||||
|
|
||||||
|
nonce := decoded[:enc.aead.NonceSize()]
|
||||||
|
encryptedData := decoded[enc.aead.NonceSize():]
|
||||||
|
|
||||||
|
plaintext, err := enc.aead.Open(nil, nonce, encryptedData, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, ErrDecryptionFailed
|
||||||
|
}
|
||||||
|
|
||||||
|
return plaintext, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateKey generates a random 256-bit key for AES-256.
|
||||||
|
func GenerateKey() ([]byte, error) {
|
||||||
|
key := make([]byte, 32) //nolint:mnd
|
||||||
|
|
||||||
|
_, err := io.ReadFull(rand.Reader, key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to generate key: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return key, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyFromString creates a key from a hex string.
|
||||||
|
func KeyFromString(hexKey string) ([]byte, error) {
|
||||||
|
key, err := hex.DecodeString(hexKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid hex key: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(key) != 16 && len(key) != 24 && len(key) != 32 {
|
||||||
|
return nil, ErrWrongKeySize
|
||||||
|
}
|
||||||
|
|
||||||
|
return key, nil
|
||||||
|
}
|
||||||
415
services/auth/go/cryto/crypto_test.go
Normal file
415
services/auth/go/cryto/crypto_test.go
Normal file
@@ -0,0 +1,415 @@
|
|||||||
|
package crypto_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
crypto "github.com/nhost/nhost/services/auth/go/cryto"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGenerateKey(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
key, err := crypto.GenerateKey()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GenerateKey failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(key) != 32 {
|
||||||
|
t.Errorf("expected key length 32, got %d", len(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate another key to ensure randomness
|
||||||
|
key2, err := crypto.GenerateKey()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GenerateKey failed on second call: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if bytes.Equal(key, key2) {
|
||||||
|
t.Error("expected different keys, got identical keys")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKeyFromString(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
hexKey string
|
||||||
|
expectError error
|
||||||
|
expectLen int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "valid AES-128 key",
|
||||||
|
hexKey: "0123456789abcdef0123456789abcdef",
|
||||||
|
expectError: nil,
|
||||||
|
expectLen: 16,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid AES-192 key",
|
||||||
|
hexKey: "0123456789abcdef0123456789abcdef0123456789abcdef",
|
||||||
|
expectError: nil,
|
||||||
|
expectLen: 24,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid AES-256 key",
|
||||||
|
hexKey: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
||||||
|
expectError: nil,
|
||||||
|
expectLen: 32,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid hex string",
|
||||||
|
hexKey: "not-a-hex-string",
|
||||||
|
expectError: hex.InvalidByteError('n'),
|
||||||
|
expectLen: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "wrong key size - too short",
|
||||||
|
hexKey: "0123456789abcdef",
|
||||||
|
expectError: crypto.ErrWrongKeySize,
|
||||||
|
expectLen: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "wrong key size - invalid length",
|
||||||
|
hexKey: "0123456789abcdef0123456789abcdef01",
|
||||||
|
expectError: crypto.ErrWrongKeySize,
|
||||||
|
expectLen: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty string",
|
||||||
|
hexKey: "",
|
||||||
|
expectError: crypto.ErrWrongKeySize,
|
||||||
|
expectLen: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range cases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
key, err := crypto.KeyFromString(tc.hexKey)
|
||||||
|
|
||||||
|
if tc.expectError != nil { //nolint:nestif
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error, got nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !errors.Is(err, tc.expectError) && err.Error() != tc.expectError.Error() {
|
||||||
|
t.Errorf("expected error %v, got %v", tc.expectError, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(key) != tc.expectLen {
|
||||||
|
t.Errorf("expected key length %d, got %d", tc.expectLen, len(key))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewEncrypter(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
keySize int
|
||||||
|
expectError bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "AES-128",
|
||||||
|
keySize: 16,
|
||||||
|
expectError: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AES-192",
|
||||||
|
keySize: 24,
|
||||||
|
expectError: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AES-256",
|
||||||
|
keySize: 32,
|
||||||
|
expectError: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid key size",
|
||||||
|
keySize: 15,
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty key",
|
||||||
|
keySize: 0,
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range cases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
key := make([]byte, tc.keySize)
|
||||||
|
enc, err := crypto.NewEncrypter(key)
|
||||||
|
|
||||||
|
if tc.expectError { //nolint:nestif
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected error, got nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if enc != nil {
|
||||||
|
t.Error("expected nil encrypter on error")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if enc == nil {
|
||||||
|
t.Fatal("expected non-nil encrypter")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncryptDecrypt(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
enc, err := crypto.NewEncrypterFromString(
|
||||||
|
"41e7109ea7cfff9e4100d29bbd58bacab0258d0fc4c0495746ed0cf166650f9d",
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create encrypter: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
plaintext []byte
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "simple string",
|
||||||
|
plaintext: []byte("FEWCQAIILM6UOYZCPFYRAPAUCIFUUUK3JUZXWKJIN4ORQNK4EQCQ"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty string",
|
||||||
|
plaintext: []byte(""),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unicode characters",
|
||||||
|
plaintext: []byte("こんにちは世界 🌍"), //nolint:gosmopolitan
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "long text",
|
||||||
|
plaintext: []byte(
|
||||||
|
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", //nolint:lll
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "binary data",
|
||||||
|
plaintext: []byte{0x00, 0x01, 0x02, 0xFF, 0xFE, 0xFD},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range cases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// Encrypt
|
||||||
|
ciphertext, err := enc.Encrypt(tc.plaintext)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("encryption failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify ciphertext is hex encoded
|
||||||
|
_, err = hex.DecodeString(string(ciphertext))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("ciphertext is not valid hex: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt
|
||||||
|
decrypted, err := enc.Decrypt(ciphertext)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("decryption failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify plaintext matches
|
||||||
|
if !bytes.Equal(tc.plaintext, decrypted) {
|
||||||
|
t.Errorf(
|
||||||
|
"decrypted text doesn't match original.\nExpected: %v\nGot: %v",
|
||||||
|
tc.plaintext,
|
||||||
|
decrypted,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncryptRandomness(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
key, err := crypto.GenerateKey()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to generate key: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
enc, err := crypto.NewEncrypter(key)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create encrypter: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
plaintext := []byte("test message")
|
||||||
|
|
||||||
|
// Encrypt the same message twice
|
||||||
|
ciphertext1, err := enc.Encrypt(plaintext)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("first encryption failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ciphertext2, err := enc.Encrypt(plaintext)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("second encryption failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ciphertexts should be different due to random nonce
|
||||||
|
if bytes.Equal(ciphertext1, ciphertext2) {
|
||||||
|
t.Error("expected different ciphertexts for same plaintext, got identical")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecryptErrors(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
key, err := crypto.GenerateKey()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to generate key: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
enc, err := crypto.NewEncrypter(key)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create encrypter: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
ciphertext []byte
|
||||||
|
expectError error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "invalid hex",
|
||||||
|
ciphertext: []byte("not-valid-hex"),
|
||||||
|
expectError: hex.InvalidByteError('n'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ciphertext too short",
|
||||||
|
ciphertext: []byte("0123"),
|
||||||
|
expectError: crypto.ErrCiphertextTooShort,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "tampered ciphertext",
|
||||||
|
ciphertext: []byte("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"),
|
||||||
|
expectError: crypto.ErrDecryptionFailed,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty ciphertext",
|
||||||
|
ciphertext: []byte(""),
|
||||||
|
expectError: crypto.ErrCiphertextTooShort,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range cases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
_, err := enc.Decrypt(tc.ciphertext)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected error, got nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !errors.Is(err, tc.expectError) && err.Error() != tc.expectError.Error() {
|
||||||
|
t.Errorf("expected error %v, got %v", tc.expectError, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecryptWithWrongKey(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
key1, err := crypto.GenerateKey()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to generate key1: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
key2, err := crypto.GenerateKey()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to generate key2: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
enc1, err := crypto.NewEncrypter(key1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create encrypter1: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
enc2, err := crypto.NewEncrypter(key2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create encrypter2: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
plaintext := []byte("secret message")
|
||||||
|
|
||||||
|
// Encrypt with first key
|
||||||
|
ciphertext, err := enc1.Encrypt(plaintext)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("encryption failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to decrypt with second key
|
||||||
|
_, err = enc2.Decrypt(ciphertext)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected decryption to fail with wrong key")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !errors.Is(err, crypto.ErrDecryptionFailed) {
|
||||||
|
t.Errorf("expected ErrDecryptionFailed, got %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMultipleEncrypters(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
key, err := crypto.GenerateKey()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to generate key: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
enc1, err := crypto.NewEncrypter(key)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create encrypter1: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
enc2, err := crypto.NewEncrypter(key)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create encrypter2: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
plaintext := []byte("test message")
|
||||||
|
|
||||||
|
// Encrypt with first encrypter
|
||||||
|
ciphertext, err := enc1.Encrypt(plaintext)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("encryption failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt with second encrypter (same key)
|
||||||
|
decrypted, err := enc2.Decrypt(ciphertext)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("decryption failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(plaintext, decrypted) {
|
||||||
|
t.Errorf("decrypted text doesn't match.\nExpected: %v\nGot: %v", plaintext, decrypted)
|
||||||
|
}
|
||||||
|
}
|
||||||
44
services/auth/go/migrations/app.go
Normal file
44
services/auth/go/migrations/app.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
|
crypto "github.com/nhost/nhost/services/auth/go/cryto"
|
||||||
|
"github.com/nhost/nhost/services/auth/go/sql"
|
||||||
|
)
|
||||||
|
|
||||||
|
func EncryptTOTPSecrets(
|
||||||
|
ctx context.Context, db *sql.Queries, encrypter *crypto.Encrypter, logger *slog.Logger,
|
||||||
|
) error {
|
||||||
|
users, err := db.GetUsersWithUnencryptedTOTPSecret(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get users with unencrypted TOTP secret: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(users) == 0 {
|
||||||
|
logger.InfoContext(ctx, "No users with unencrypted TOTP secret found")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.InfoContext(ctx, "Encrypting TOTP secrets for users", slog.Int("count", len(users)))
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
encryptedTOTPSecret, err := encrypter.Encrypt([]byte(user.TotpSecret.String))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to encrypt TOTP secret for user %s: %w", user.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.UpdateUserTotpSecret(ctx, sql.UpdateUserTotpSecretParams{
|
||||||
|
ID: user.ID,
|
||||||
|
TotpSecret: sql.Text(string(encryptedTOTPSecret)),
|
||||||
|
}); err != nil {
|
||||||
|
return fmt.Errorf("failed to update TOTP secret for user %s: %w", user.ID, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.InfoContext(ctx, "Successfully encrypted TOTP secrets for all users")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -11,8 +12,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
timeout = 10
|
timeout = 10
|
||||||
hasuraDBName = "default"
|
hasuraDBName = "default"
|
||||||
|
errorCodeAlreadyTracked = "already-tracked"
|
||||||
|
errorCodeAlreadyExists = "already-exists"
|
||||||
)
|
)
|
||||||
|
|
||||||
type hasuraErrResponse struct {
|
type hasuraErrResponse struct {
|
||||||
@@ -21,6 +24,19 @@ type hasuraErrResponse struct {
|
|||||||
Code string `json:"code"`
|
Code string `json:"code"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type metadataError struct {
|
||||||
|
code string
|
||||||
|
msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *metadataError) Error() string {
|
||||||
|
return e.msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *metadataError) Code() string {
|
||||||
|
return e.code
|
||||||
|
}
|
||||||
|
|
||||||
func postMetadata(ctx context.Context, url, hasuraSecret string, data any) error {
|
func postMetadata(ctx context.Context, url, hasuraSecret string, data any) error {
|
||||||
client := &http.Client{ //nolint: exhaustruct
|
client := &http.Client{ //nolint: exhaustruct
|
||||||
Timeout: time.Second * timeout,
|
Timeout: time.Second * timeout,
|
||||||
@@ -57,8 +73,12 @@ func postMetadata(ctx context.Context, url, hasuraSecret string, data any) error
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if errResponse.Code == "already-tracked" || errResponse.Code == "already-exists" {
|
if errResponse.Code == errorCodeAlreadyTracked ||
|
||||||
return nil
|
errResponse.Code == errorCodeAlreadyExists {
|
||||||
|
return &metadataError{
|
||||||
|
code: errResponse.Code,
|
||||||
|
msg: errResponse.Error,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("status_code: %d\nresponse: %s", resp.StatusCode, b) //nolint: err113
|
return fmt.Errorf("status_code: %d\nresponse: %s", resp.StatusCode, b) //nolint: err113
|
||||||
@@ -68,8 +88,9 @@ func postMetadata(ctx context.Context, url, hasuraSecret string, data any) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TrackTable struct {
|
type TrackTable struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Args PgTrackTableArgs `json:"args"`
|
Args PgTrackTableArgs `json:"args"`
|
||||||
|
IsEnum bool `json:"is_enum,omitempty"` //nolint: tagliatelle
|
||||||
}
|
}
|
||||||
|
|
||||||
type Table struct {
|
type Table struct {
|
||||||
@@ -96,9 +117,29 @@ type Configuration struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type PgTrackTableArgs struct {
|
type PgTrackTableArgs struct {
|
||||||
Source string `json:"source"`
|
Source string `json:"source"`
|
||||||
Table Table `json:"table"`
|
Table Table `json:"table"`
|
||||||
Configuration Configuration `json:"configuration"`
|
Configuration Configuration `json:"configuration"`
|
||||||
|
ObjectRelationships []ObjectRelationshipConfig `json:"object_relationships,omitempty"` //nolint: tagliatelle
|
||||||
|
ArrayRelationships []ArrayRelationshipConfig `json:"array_relationships,omitempty"` //nolint: tagliatelle
|
||||||
|
}
|
||||||
|
|
||||||
|
type ObjectRelationshipConfig struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Using ObjectRelationshipConfigUsing `json:"using"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ObjectRelationshipConfigUsing struct {
|
||||||
|
ForeignKeyConstraintOn any `json:"foreign_key_constraint_on"` //nolint: tagliatelle
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArrayRelationshipConfig struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Using ArrayRelationshipConfigUsing `json:"using"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArrayRelationshipConfigUsing struct {
|
||||||
|
ForeignKeyConstraintOn ForeignKeyConstraintOn `json:"foreign_key_constraint_on"` //nolint: tagliatelle
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateObjectRelationship struct {
|
type CreateObjectRelationship struct {
|
||||||
@@ -150,14 +191,126 @@ type DropRelationshipArgs struct {
|
|||||||
Relationship string `json:"relationship"`
|
Relationship string `json:"relationship"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SetTableCustomization struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Args SetTableCustomizationArgs `json:"args"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SetTableCustomizationArgs struct {
|
||||||
|
Source string `json:"source"`
|
||||||
|
Table Table `json:"table"`
|
||||||
|
Configuration Configuration `json:"configuration"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyTableCustomization(
|
||||||
|
ctx context.Context,
|
||||||
|
url, hasuraSecret string,
|
||||||
|
table TrackTable,
|
||||||
|
) error {
|
||||||
|
customization := SetTableCustomization{
|
||||||
|
Type: "pg_set_table_customization",
|
||||||
|
Args: SetTableCustomizationArgs{
|
||||||
|
Source: table.Args.Source,
|
||||||
|
Table: table.Args.Table,
|
||||||
|
Configuration: table.Args.Configuration,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return postMetadata(ctx, url, hasuraSecret, customization)
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyObjectRelationships(
|
||||||
|
ctx context.Context,
|
||||||
|
url, hasuraSecret string,
|
||||||
|
table TrackTable,
|
||||||
|
) error {
|
||||||
|
for _, rel := range table.Args.ObjectRelationships {
|
||||||
|
relationship := CreateObjectRelationship{
|
||||||
|
Type: "pg_create_object_relationship",
|
||||||
|
Args: CreateObjectRelationshipArgs{
|
||||||
|
Source: table.Args.Source,
|
||||||
|
Table: table.Args.Table,
|
||||||
|
Name: rel.Name,
|
||||||
|
Using: CreateObjectRelationshipUsing{
|
||||||
|
ForeignKeyConstraintOn: func() []string {
|
||||||
|
// Handle both string and array cases
|
||||||
|
switch v := rel.Using.ForeignKeyConstraintOn.(type) {
|
||||||
|
case string:
|
||||||
|
return []string{v}
|
||||||
|
case []string:
|
||||||
|
return v
|
||||||
|
default:
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := postMetadata(ctx, url, hasuraSecret, relationship); err != nil {
|
||||||
|
var metaErr *metadataError
|
||||||
|
if ok := errors.As(err, &metaErr); ok && metaErr.Code() == errorCodeAlreadyExists {
|
||||||
|
continue // Skip if relationship already exists
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf(
|
||||||
|
"problem creating object relationship %s for table %s.%s: %w",
|
||||||
|
rel.Name,
|
||||||
|
table.Args.Table.Schema,
|
||||||
|
table.Args.Table.Name,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyArrayRelationships(
|
||||||
|
ctx context.Context,
|
||||||
|
url, hasuraSecret string,
|
||||||
|
table TrackTable,
|
||||||
|
) error {
|
||||||
|
for _, rel := range table.Args.ArrayRelationships {
|
||||||
|
relationship := CreateArrayRelationship{
|
||||||
|
Type: "pg_create_array_relationship",
|
||||||
|
Args: CreateArrayRelationshipArgs{
|
||||||
|
Source: table.Args.Source,
|
||||||
|
Table: table.Args.Table,
|
||||||
|
Name: rel.Name,
|
||||||
|
Using: CreateArrayRelationshipUsing{
|
||||||
|
ForeignKeyConstraintOn: rel.Using.ForeignKeyConstraintOn,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := postMetadata(ctx, url, hasuraSecret, relationship); err != nil {
|
||||||
|
var metaErr *metadataError
|
||||||
|
if ok := errors.As(err, &metaErr); ok && metaErr.Code() == errorCodeAlreadyExists {
|
||||||
|
continue // Skip if relationship already exists
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf(
|
||||||
|
"problem creating array relationship %s for table %s.%s: %w",
|
||||||
|
rel.Name,
|
||||||
|
table.Args.Table.Schema,
|
||||||
|
table.Args.Table.Name,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func ApplyHasuraMetadata( //nolint: funlen,maintidx
|
func ApplyHasuraMetadata( //nolint: funlen,maintidx
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
url, hasuraSecret string,
|
url, hasuraSecret string,
|
||||||
) error {
|
) error {
|
||||||
authTables := []TrackTable{
|
authTables := []TrackTable{
|
||||||
{
|
{ //nolint:exhaustruct
|
||||||
Type: "pg_track_table",
|
Type: "pg_track_table",
|
||||||
Args: PgTrackTableArgs{
|
Args: PgTrackTableArgs{ //nolint:exhaustruct
|
||||||
Source: hasuraDBName,
|
Source: hasuraDBName,
|
||||||
Table: Table{
|
Table: Table{
|
||||||
Schema: "auth",
|
Schema: "auth",
|
||||||
@@ -184,8 +337,9 @@ func ApplyHasuraMetadata( //nolint: funlen,maintidx
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: "pg_track_table",
|
Type: "pg_track_table",
|
||||||
Args: PgTrackTableArgs{
|
IsEnum: true,
|
||||||
|
Args: PgTrackTableArgs{ //nolint:exhaustruct
|
||||||
Source: hasuraDBName,
|
Source: hasuraDBName,
|
||||||
Table: Table{
|
Table: Table{
|
||||||
Schema: "auth",
|
Schema: "auth",
|
||||||
@@ -209,11 +363,25 @@ func ApplyHasuraMetadata( //nolint: funlen,maintidx
|
|||||||
"comment": "comment",
|
"comment": "comment",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ArrayRelationships: []ArrayRelationshipConfig{
|
||||||
|
{
|
||||||
|
Name: "refreshTokens",
|
||||||
|
Using: ArrayRelationshipConfigUsing{
|
||||||
|
ForeignKeyConstraintOn: ForeignKeyConstraintOn{
|
||||||
|
Table: Table{
|
||||||
|
Schema: "auth",
|
||||||
|
Name: "refresh_tokens",
|
||||||
|
},
|
||||||
|
Columns: []string{"type"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{ //nolint:exhaustruct
|
||||||
Type: "pg_track_table",
|
Type: "pg_track_table",
|
||||||
Args: PgTrackTableArgs{
|
Args: PgTrackTableArgs{ //nolint:exhaustruct
|
||||||
Source: hasuraDBName,
|
Source: hasuraDBName,
|
||||||
Table: Table{
|
Table: Table{
|
||||||
Schema: "auth",
|
Schema: "auth",
|
||||||
@@ -239,11 +407,19 @@ func ApplyHasuraMetadata( //nolint: funlen,maintidx
|
|||||||
"user_id": "userId",
|
"user_id": "userId",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ObjectRelationships: []ObjectRelationshipConfig{
|
||||||
|
{
|
||||||
|
Name: "user",
|
||||||
|
Using: ObjectRelationshipConfigUsing{
|
||||||
|
ForeignKeyConstraintOn: "user_id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{ //nolint:exhaustruct
|
||||||
Type: "pg_track_table",
|
Type: "pg_track_table",
|
||||||
Args: PgTrackTableArgs{
|
Args: PgTrackTableArgs{ //nolint:exhaustruct
|
||||||
Source: hasuraDBName,
|
Source: hasuraDBName,
|
||||||
Table: Table{
|
Table: Table{
|
||||||
Schema: "auth",
|
Schema: "auth",
|
||||||
@@ -266,11 +442,37 @@ func ApplyHasuraMetadata( //nolint: funlen,maintidx
|
|||||||
"role": "role",
|
"role": "role",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ArrayRelationships: []ArrayRelationshipConfig{
|
||||||
|
{
|
||||||
|
Name: "userRoles",
|
||||||
|
Using: ArrayRelationshipConfigUsing{
|
||||||
|
ForeignKeyConstraintOn: ForeignKeyConstraintOn{
|
||||||
|
Table: Table{
|
||||||
|
Schema: "auth",
|
||||||
|
Name: "user_roles",
|
||||||
|
},
|
||||||
|
Columns: []string{"role"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "usersByDefaultRole",
|
||||||
|
Using: ArrayRelationshipConfigUsing{
|
||||||
|
ForeignKeyConstraintOn: ForeignKeyConstraintOn{
|
||||||
|
Table: Table{
|
||||||
|
Schema: "auth",
|
||||||
|
Name: "users",
|
||||||
|
},
|
||||||
|
Columns: []string{"default_role"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{ //nolint:exhaustruct
|
||||||
Type: "pg_track_table",
|
Type: "pg_track_table",
|
||||||
Args: PgTrackTableArgs{
|
Args: PgTrackTableArgs{ //nolint:exhaustruct
|
||||||
Source: hasuraDBName,
|
Source: hasuraDBName,
|
||||||
Table: Table{
|
Table: Table{
|
||||||
Schema: "auth",
|
Schema: "auth",
|
||||||
@@ -300,11 +502,25 @@ func ApplyHasuraMetadata( //nolint: funlen,maintidx
|
|||||||
"provider_user_id": "providerUserId",
|
"provider_user_id": "providerUserId",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ObjectRelationships: []ObjectRelationshipConfig{
|
||||||
|
{
|
||||||
|
Name: "user",
|
||||||
|
Using: ObjectRelationshipConfigUsing{
|
||||||
|
ForeignKeyConstraintOn: "user_id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "provider",
|
||||||
|
Using: ObjectRelationshipConfigUsing{
|
||||||
|
ForeignKeyConstraintOn: "provider_id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{ //nolint:exhaustruct
|
||||||
Type: "pg_track_table",
|
Type: "pg_track_table",
|
||||||
Args: PgTrackTableArgs{
|
Args: PgTrackTableArgs{ //nolint:exhaustruct
|
||||||
Source: hasuraDBName,
|
Source: hasuraDBName,
|
||||||
Table: Table{
|
Table: Table{
|
||||||
Schema: "auth",
|
Schema: "auth",
|
||||||
@@ -330,9 +546,23 @@ func ApplyHasuraMetadata( //nolint: funlen,maintidx
|
|||||||
"role": "role",
|
"role": "role",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ObjectRelationships: []ObjectRelationshipConfig{
|
||||||
|
{
|
||||||
|
Name: "user",
|
||||||
|
Using: ObjectRelationshipConfigUsing{
|
||||||
|
ForeignKeyConstraintOn: "user_id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "roleByRole",
|
||||||
|
Using: ObjectRelationshipConfigUsing{
|
||||||
|
ForeignKeyConstraintOn: "role",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{ //nolint:exhaustruct
|
||||||
Type: "pg_track_table",
|
Type: "pg_track_table",
|
||||||
Args: PgTrackTableArgs{
|
Args: PgTrackTableArgs{
|
||||||
Source: hasuraDBName,
|
Source: hasuraDBName,
|
||||||
@@ -380,11 +610,69 @@ func ApplyHasuraMetadata( //nolint: funlen,maintidx
|
|||||||
"webauthn_current_challenge": "currentChallenge",
|
"webauthn_current_challenge": "currentChallenge",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ObjectRelationships: []ObjectRelationshipConfig{
|
||||||
|
{
|
||||||
|
Name: "defaultRoleByRole",
|
||||||
|
Using: ObjectRelationshipConfigUsing{
|
||||||
|
ForeignKeyConstraintOn: "default_role",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ArrayRelationships: []ArrayRelationshipConfig{
|
||||||
|
{
|
||||||
|
Name: "userProviders",
|
||||||
|
Using: ArrayRelationshipConfigUsing{
|
||||||
|
ForeignKeyConstraintOn: ForeignKeyConstraintOn{
|
||||||
|
Table: Table{
|
||||||
|
Schema: "auth",
|
||||||
|
Name: "user_providers",
|
||||||
|
},
|
||||||
|
Columns: []string{"user_id"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "roles",
|
||||||
|
Using: ArrayRelationshipConfigUsing{
|
||||||
|
ForeignKeyConstraintOn: ForeignKeyConstraintOn{
|
||||||
|
Table: Table{
|
||||||
|
Schema: "auth",
|
||||||
|
Name: "user_roles",
|
||||||
|
},
|
||||||
|
Columns: []string{"user_id"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "refreshTokens",
|
||||||
|
Using: ArrayRelationshipConfigUsing{
|
||||||
|
ForeignKeyConstraintOn: ForeignKeyConstraintOn{
|
||||||
|
Table: Table{
|
||||||
|
Schema: "auth",
|
||||||
|
Name: "refresh_tokens",
|
||||||
|
},
|
||||||
|
Columns: []string{"user_id"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "securityKeys",
|
||||||
|
Using: ArrayRelationshipConfigUsing{
|
||||||
|
ForeignKeyConstraintOn: ForeignKeyConstraintOn{
|
||||||
|
Table: Table{
|
||||||
|
Schema: "auth",
|
||||||
|
Name: "user_security_keys",
|
||||||
|
},
|
||||||
|
Columns: []string{"user_id"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{ //nolint:exhaustruct
|
||||||
Type: "pg_track_table",
|
Type: "pg_track_table",
|
||||||
Args: PgTrackTableArgs{
|
Args: PgTrackTableArgs{ //nolint:exhaustruct
|
||||||
Source: hasuraDBName,
|
Source: hasuraDBName,
|
||||||
Table: Table{
|
Table: Table{
|
||||||
Schema: "auth",
|
Schema: "auth",
|
||||||
@@ -407,11 +695,25 @@ func ApplyHasuraMetadata( //nolint: funlen,maintidx
|
|||||||
"id": "id",
|
"id": "id",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ArrayRelationships: []ArrayRelationshipConfig{
|
||||||
|
{
|
||||||
|
Name: "userProviders",
|
||||||
|
Using: ArrayRelationshipConfigUsing{
|
||||||
|
ForeignKeyConstraintOn: ForeignKeyConstraintOn{
|
||||||
|
Table: Table{
|
||||||
|
Schema: "auth",
|
||||||
|
Name: "user_providers",
|
||||||
|
},
|
||||||
|
Columns: []string{"provider_id"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{ //nolint:exhaustruct
|
||||||
Type: "pg_track_table",
|
Type: "pg_track_table",
|
||||||
Args: PgTrackTableArgs{
|
Args: PgTrackTableArgs{ //nolint:exhaustruct
|
||||||
Source: hasuraDBName,
|
Source: hasuraDBName,
|
||||||
Table: Table{
|
Table: Table{
|
||||||
Schema: "auth",
|
Schema: "auth",
|
||||||
@@ -437,15 +739,49 @@ func ApplyHasuraMetadata( //nolint: funlen,maintidx
|
|||||||
"credential_public_key": "credentialPublicKey",
|
"credential_public_key": "credentialPublicKey",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ObjectRelationships: []ObjectRelationshipConfig{
|
||||||
|
{
|
||||||
|
Name: "user",
|
||||||
|
Using: ObjectRelationshipConfigUsing{
|
||||||
|
ForeignKeyConstraintOn: "user_id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track each table (will skip if already tracked due to existing error handling)
|
|
||||||
for _, table := range authTables {
|
for _, table := range authTables {
|
||||||
if err := postMetadata(ctx, url, hasuraSecret, table); err != nil {
|
err := postMetadata(ctx, url, hasuraSecret, table)
|
||||||
return fmt.Errorf("problem adding metadata for table %s.%s: %w",
|
if err != nil {
|
||||||
table.Args.Table.Schema, table.Args.Table.Name, err)
|
var metaErr *metadataError
|
||||||
|
if ok := errors.As(err, &metaErr); ok && metaErr.Code() == errorCodeAlreadyTracked {
|
||||||
|
if err := applyTableCustomization(ctx, url, hasuraSecret, table); err != nil {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"problem updating customization for table %s.%s: %w",
|
||||||
|
table.Args.Table.Schema,
|
||||||
|
table.Args.Table.Name,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"problem adding metadata for table %s.%s: %w",
|
||||||
|
table.Args.Table.Schema,
|
||||||
|
table.Args.Table.Name,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, table := range authTables {
|
||||||
|
if err := applyObjectRelationships(ctx, url, hasuraSecret, table); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := applyArrayRelationships(ctx, url, hasuraSecret, table); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -402,3 +402,7 @@ INSERT INTO auth.roles (role)
|
|||||||
SELECT unnest(@roles::TEXT[])
|
SELECT unnest(@roles::TEXT[])
|
||||||
ON CONFLICT (role) DO NOTHING
|
ON CONFLICT (role) DO NOTHING
|
||||||
RETURNING role;
|
RETURNING role;
|
||||||
|
|
||||||
|
-- name: GetUsersWithUnencryptedTOTPSecret :many
|
||||||
|
SELECT * FROM auth.users
|
||||||
|
WHERE LENGTH(totp_secret) < 64;
|
||||||
|
|||||||
@@ -494,6 +494,57 @@ func (q *Queries) GetUserRoles(ctx context.Context, userID uuid.UUID) ([]AuthUse
|
|||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getUsersWithUnencryptedTOTPSecret = `-- name: GetUsersWithUnencryptedTOTPSecret :many
|
||||||
|
SELECT id, created_at, updated_at, last_seen, disabled, display_name, avatar_url, locale, email, phone_number, password_hash, email_verified, phone_number_verified, new_email, otp_method_last_used, otp_hash, otp_hash_expires_at, default_role, is_anonymous, totp_secret, active_mfa_type, ticket, ticket_expires_at, metadata, webauthn_current_challenge FROM auth.users
|
||||||
|
WHERE LENGTH(totp_secret) < 64
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetUsersWithUnencryptedTOTPSecret(ctx context.Context) ([]AuthUser, error) {
|
||||||
|
rows, err := q.db.Query(ctx, getUsersWithUnencryptedTOTPSecret)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []AuthUser
|
||||||
|
for rows.Next() {
|
||||||
|
var i AuthUser
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
&i.LastSeen,
|
||||||
|
&i.Disabled,
|
||||||
|
&i.DisplayName,
|
||||||
|
&i.AvatarUrl,
|
||||||
|
&i.Locale,
|
||||||
|
&i.Email,
|
||||||
|
&i.PhoneNumber,
|
||||||
|
&i.PasswordHash,
|
||||||
|
&i.EmailVerified,
|
||||||
|
&i.PhoneNumberVerified,
|
||||||
|
&i.NewEmail,
|
||||||
|
&i.OtpMethodLastUsed,
|
||||||
|
&i.OtpHash,
|
||||||
|
&i.OtpHashExpiresAt,
|
||||||
|
&i.DefaultRole,
|
||||||
|
&i.IsAnonymous,
|
||||||
|
&i.TotpSecret,
|
||||||
|
&i.ActiveMfaType,
|
||||||
|
&i.Ticket,
|
||||||
|
&i.TicketExpiresAt,
|
||||||
|
&i.Metadata,
|
||||||
|
&i.WebauthnCurrentChallenge,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
const insertRefreshtoken = `-- name: InsertRefreshtoken :one
|
const insertRefreshtoken = `-- name: InsertRefreshtoken :one
|
||||||
INSERT INTO auth.refresh_tokens (user_id, refresh_token_hash, expires_at, type, metadata)
|
INSERT INTO auth.refresh_tokens (user_id, refresh_token_hash, expires_at, type, metadata)
|
||||||
VALUES ($1, $2, $3, $4, $5)
|
VALUES ($1, $2, $3, $4, $5)
|
||||||
|
|||||||
30
vendor/github.com/nhost/be/services/mimir/graph/config_validate.go
generated
vendored
30
vendor/github.com/nhost/be/services/mimir/graph/config_validate.go
generated
vendored
@@ -21,30 +21,6 @@ const (
|
|||||||
pitrMinVersion = 20250311
|
pitrMinVersion = 20250311
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *mutationResolver) configValidateVerifyPersistentVolumeEncryption(
|
|
||||||
desiredState int32,
|
|
||||||
oldApp *App,
|
|
||||||
newApp *App,
|
|
||||||
) error {
|
|
||||||
if oldApp == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
oldEncrypted := deptr(oldApp.SystemConfig.GetPersistentVolumesEncrypted())
|
|
||||||
newEncrypted := deptr(newApp.SystemConfig.GetPersistentVolumesEncrypted())
|
|
||||||
|
|
||||||
if oldEncrypted && !newEncrypted {
|
|
||||||
return ErrPersVolEncryptionCantBeDis
|
|
||||||
}
|
|
||||||
|
|
||||||
if !oldEncrypted && newEncrypted &&
|
|
||||||
!slices.Contains([]int32{appPaused, appEmpty}, desiredState) {
|
|
||||||
return ErrPersVolEncryptionCantBeChanged
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *mutationResolver) configValidateVerifyPostgresVersionChange(
|
func (r *mutationResolver) configValidateVerifyPostgresVersionChange(
|
||||||
desiredState int32,
|
desiredState int32,
|
||||||
oldApp *App,
|
oldApp *App,
|
||||||
@@ -135,12 +111,6 @@ func (r *mutationResolver) configValidate(
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := r.configValidateVerifyPersistentVolumeEncryption(
|
|
||||||
desiredState, oldApp, newApp,
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := r.verifyPostgresVersionForPitr(newApp); err != nil {
|
if err := r.verifyPostgresVersionForPitr(newApp); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
232
vendor/github.com/nhost/be/services/mimir/graph/generated/generated.go
generated
vendored
232
vendor/github.com/nhost/be/services/mimir/graph/generated/generated.go
generated
vendored
@@ -688,11 +688,13 @@ type ComplexityRoot struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConfigSystemConfigPostgres struct {
|
ConfigSystemConfigPostgres struct {
|
||||||
ConnectionString func(childComplexity int) int
|
ConnectionString func(childComplexity int) int
|
||||||
Database func(childComplexity int) int
|
Database func(childComplexity int) int
|
||||||
Disk func(childComplexity int) int
|
Disk func(childComplexity int) int
|
||||||
Enabled func(childComplexity int) int
|
Enabled func(childComplexity int) int
|
||||||
MajorVersion func(childComplexity int) int
|
EncryptColumnKey func(childComplexity int) int
|
||||||
|
MajorVersion func(childComplexity int) int
|
||||||
|
OldEncryptColumnKey func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigSystemConfigPostgresConnectionString struct {
|
ConfigSystemConfigPostgresConnectionString struct {
|
||||||
@@ -3208,6 +3210,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
|||||||
|
|
||||||
return e.complexity.ConfigSystemConfigPostgres.Enabled(childComplexity), true
|
return e.complexity.ConfigSystemConfigPostgres.Enabled(childComplexity), true
|
||||||
|
|
||||||
|
case "ConfigSystemConfigPostgres.encryptColumnKey":
|
||||||
|
if e.complexity.ConfigSystemConfigPostgres.EncryptColumnKey == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.ConfigSystemConfigPostgres.EncryptColumnKey(childComplexity), true
|
||||||
|
|
||||||
case "ConfigSystemConfigPostgres.majorVersion":
|
case "ConfigSystemConfigPostgres.majorVersion":
|
||||||
if e.complexity.ConfigSystemConfigPostgres.MajorVersion == nil {
|
if e.complexity.ConfigSystemConfigPostgres.MajorVersion == nil {
|
||||||
break
|
break
|
||||||
@@ -3215,6 +3224,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
|||||||
|
|
||||||
return e.complexity.ConfigSystemConfigPostgres.MajorVersion(childComplexity), true
|
return e.complexity.ConfigSystemConfigPostgres.MajorVersion(childComplexity), true
|
||||||
|
|
||||||
|
case "ConfigSystemConfigPostgres.oldEncryptColumnKey":
|
||||||
|
if e.complexity.ConfigSystemConfigPostgres.OldEncryptColumnKey == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.ConfigSystemConfigPostgres.OldEncryptColumnKey(childComplexity), true
|
||||||
|
|
||||||
case "ConfigSystemConfigPostgresConnectionString.auth":
|
case "ConfigSystemConfigPostgresConnectionString.auth":
|
||||||
if e.complexity.ConfigSystemConfigPostgresConnectionString.Auth == nil {
|
if e.complexity.ConfigSystemConfigPostgresConnectionString.Auth == nil {
|
||||||
break
|
break
|
||||||
@@ -8234,28 +8250,40 @@ type ConfigSystemConfigPostgres {
|
|||||||
connectionString: ConfigSystemConfigPostgresConnectionString!
|
connectionString: ConfigSystemConfigPostgresConnectionString!
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
disk: ConfigSystemConfigPostgresDisk
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
encryptColumnKey: String
|
||||||
|
"""
|
||||||
|
|
||||||
"""
|
"""
|
||||||
database: String!
|
database: String!
|
||||||
"""
|
"""
|
||||||
|
|
||||||
"""
|
"""
|
||||||
disk: ConfigSystemConfigPostgresDisk
|
oldEncryptColumnKey: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input ConfigSystemConfigPostgresUpdateInput {
|
input ConfigSystemConfigPostgresUpdateInput {
|
||||||
enabled: Boolean
|
enabled: Boolean
|
||||||
majorVersion: String
|
majorVersion: String
|
||||||
connectionString: ConfigSystemConfigPostgresConnectionStringUpdateInput
|
connectionString: ConfigSystemConfigPostgresConnectionStringUpdateInput
|
||||||
database: String
|
|
||||||
disk: ConfigSystemConfigPostgresDiskUpdateInput
|
disk: ConfigSystemConfigPostgresDiskUpdateInput
|
||||||
|
encryptColumnKey: String
|
||||||
|
database: String
|
||||||
|
oldEncryptColumnKey: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input ConfigSystemConfigPostgresInsertInput {
|
input ConfigSystemConfigPostgresInsertInput {
|
||||||
enabled: Boolean
|
enabled: Boolean
|
||||||
majorVersion: String
|
majorVersion: String
|
||||||
connectionString: ConfigSystemConfigPostgresConnectionStringInsertInput!
|
connectionString: ConfigSystemConfigPostgresConnectionStringInsertInput!
|
||||||
database: String!
|
|
||||||
disk: ConfigSystemConfigPostgresDiskInsertInput
|
disk: ConfigSystemConfigPostgresDiskInsertInput
|
||||||
|
encryptColumnKey: String
|
||||||
|
database: String!
|
||||||
|
oldEncryptColumnKey: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input ConfigSystemConfigPostgresComparisonExp {
|
input ConfigSystemConfigPostgresComparisonExp {
|
||||||
@@ -8265,8 +8293,10 @@ input ConfigSystemConfigPostgresComparisonExp {
|
|||||||
enabled: ConfigBooleanComparisonExp
|
enabled: ConfigBooleanComparisonExp
|
||||||
majorVersion: ConfigStringComparisonExp
|
majorVersion: ConfigStringComparisonExp
|
||||||
connectionString: ConfigSystemConfigPostgresConnectionStringComparisonExp
|
connectionString: ConfigSystemConfigPostgresConnectionStringComparisonExp
|
||||||
database: ConfigStringComparisonExp
|
|
||||||
disk: ConfigSystemConfigPostgresDiskComparisonExp
|
disk: ConfigSystemConfigPostgresDiskComparisonExp
|
||||||
|
encryptColumnKey: ConfigStringComparisonExp
|
||||||
|
database: ConfigStringComparisonExp
|
||||||
|
oldEncryptColumnKey: ConfigStringComparisonExp
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -25447,10 +25477,14 @@ func (ec *executionContext) fieldContext_ConfigSystemConfig_postgres(_ context.C
|
|||||||
return ec.fieldContext_ConfigSystemConfigPostgres_majorVersion(ctx, field)
|
return ec.fieldContext_ConfigSystemConfigPostgres_majorVersion(ctx, field)
|
||||||
case "connectionString":
|
case "connectionString":
|
||||||
return ec.fieldContext_ConfigSystemConfigPostgres_connectionString(ctx, field)
|
return ec.fieldContext_ConfigSystemConfigPostgres_connectionString(ctx, field)
|
||||||
case "database":
|
|
||||||
return ec.fieldContext_ConfigSystemConfigPostgres_database(ctx, field)
|
|
||||||
case "disk":
|
case "disk":
|
||||||
return ec.fieldContext_ConfigSystemConfigPostgres_disk(ctx, field)
|
return ec.fieldContext_ConfigSystemConfigPostgres_disk(ctx, field)
|
||||||
|
case "encryptColumnKey":
|
||||||
|
return ec.fieldContext_ConfigSystemConfigPostgres_encryptColumnKey(ctx, field)
|
||||||
|
case "database":
|
||||||
|
return ec.fieldContext_ConfigSystemConfigPostgres_database(ctx, field)
|
||||||
|
case "oldEncryptColumnKey":
|
||||||
|
return ec.fieldContext_ConfigSystemConfigPostgres_oldEncryptColumnKey(ctx, field)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("no field named %q was found under type ConfigSystemConfigPostgres", field.Name)
|
return nil, fmt.Errorf("no field named %q was found under type ConfigSystemConfigPostgres", field.Name)
|
||||||
},
|
},
|
||||||
@@ -25807,6 +25841,94 @@ func (ec *executionContext) fieldContext_ConfigSystemConfigPostgres_connectionSt
|
|||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _ConfigSystemConfigPostgres_disk(ctx context.Context, field graphql.CollectedField, obj *model.ConfigSystemConfigPostgres) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_ConfigSystemConfigPostgres_disk(ctx, field)
|
||||||
|
if err != nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.Disk, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*model.ConfigSystemConfigPostgresDisk)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalOConfigSystemConfigPostgresDisk2ᚖgithubᚗcomᚋnhostᚋbeᚋservicesᚋmimirᚋmodelᚐConfigSystemConfigPostgresDisk(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_ConfigSystemConfigPostgres_disk(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "ConfigSystemConfigPostgres",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
switch field.Name {
|
||||||
|
case "iops":
|
||||||
|
return ec.fieldContext_ConfigSystemConfigPostgresDisk_iops(ctx, field)
|
||||||
|
case "tput":
|
||||||
|
return ec.fieldContext_ConfigSystemConfigPostgresDisk_tput(ctx, field)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("no field named %q was found under type ConfigSystemConfigPostgresDisk", field.Name)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _ConfigSystemConfigPostgres_encryptColumnKey(ctx context.Context, field graphql.CollectedField, obj *model.ConfigSystemConfigPostgres) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_ConfigSystemConfigPostgres_encryptColumnKey(ctx, field)
|
||||||
|
if err != nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.EncryptColumnKey, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*string)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_ConfigSystemConfigPostgres_encryptColumnKey(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "ConfigSystemConfigPostgres",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type String does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _ConfigSystemConfigPostgres_database(ctx context.Context, field graphql.CollectedField, obj *model.ConfigSystemConfigPostgres) (ret graphql.Marshaler) {
|
func (ec *executionContext) _ConfigSystemConfigPostgres_database(ctx context.Context, field graphql.CollectedField, obj *model.ConfigSystemConfigPostgres) (ret graphql.Marshaler) {
|
||||||
fc, err := ec.fieldContext_ConfigSystemConfigPostgres_database(ctx, field)
|
fc, err := ec.fieldContext_ConfigSystemConfigPostgres_database(ctx, field)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -25851,8 +25973,8 @@ func (ec *executionContext) fieldContext_ConfigSystemConfigPostgres_database(_ c
|
|||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _ConfigSystemConfigPostgres_disk(ctx context.Context, field graphql.CollectedField, obj *model.ConfigSystemConfigPostgres) (ret graphql.Marshaler) {
|
func (ec *executionContext) _ConfigSystemConfigPostgres_oldEncryptColumnKey(ctx context.Context, field graphql.CollectedField, obj *model.ConfigSystemConfigPostgres) (ret graphql.Marshaler) {
|
||||||
fc, err := ec.fieldContext_ConfigSystemConfigPostgres_disk(ctx, field)
|
fc, err := ec.fieldContext_ConfigSystemConfigPostgres_oldEncryptColumnKey(ctx, field)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return graphql.Null
|
return graphql.Null
|
||||||
}
|
}
|
||||||
@@ -25865,7 +25987,7 @@ func (ec *executionContext) _ConfigSystemConfigPostgres_disk(ctx context.Context
|
|||||||
}()
|
}()
|
||||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||||
ctx = rctx // use context from middleware stack in children
|
ctx = rctx // use context from middleware stack in children
|
||||||
return obj.Disk, nil
|
return obj.OldEncryptColumnKey, nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ec.Error(ctx, err)
|
ec.Error(ctx, err)
|
||||||
@@ -25874,25 +25996,19 @@ func (ec *executionContext) _ConfigSystemConfigPostgres_disk(ctx context.Context
|
|||||||
if resTmp == nil {
|
if resTmp == nil {
|
||||||
return graphql.Null
|
return graphql.Null
|
||||||
}
|
}
|
||||||
res := resTmp.(*model.ConfigSystemConfigPostgresDisk)
|
res := resTmp.(*string)
|
||||||
fc.Result = res
|
fc.Result = res
|
||||||
return ec.marshalOConfigSystemConfigPostgresDisk2ᚖgithubᚗcomᚋnhostᚋbeᚋservicesᚋmimirᚋmodelᚐConfigSystemConfigPostgresDisk(ctx, field.Selections, res)
|
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) fieldContext_ConfigSystemConfigPostgres_disk(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
func (ec *executionContext) fieldContext_ConfigSystemConfigPostgres_oldEncryptColumnKey(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
fc = &graphql.FieldContext{
|
fc = &graphql.FieldContext{
|
||||||
Object: "ConfigSystemConfigPostgres",
|
Object: "ConfigSystemConfigPostgres",
|
||||||
Field: field,
|
Field: field,
|
||||||
IsMethod: false,
|
IsMethod: false,
|
||||||
IsResolver: false,
|
IsResolver: false,
|
||||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
switch field.Name {
|
return nil, errors.New("field of type String does not have child fields")
|
||||||
case "iops":
|
|
||||||
return ec.fieldContext_ConfigSystemConfigPostgresDisk_iops(ctx, field)
|
|
||||||
case "tput":
|
|
||||||
return ec.fieldContext_ConfigSystemConfigPostgresDisk_tput(ctx, field)
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("no field named %q was found under type ConfigSystemConfigPostgresDisk", field.Name)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return fc, nil
|
return fc, nil
|
||||||
@@ -41018,7 +41134,7 @@ func (ec *executionContext) unmarshalInputConfigSystemConfigPostgresComparisonEx
|
|||||||
asMap[k] = v
|
asMap[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldsInOrder := [...]string{"_and", "_not", "_or", "enabled", "majorVersion", "connectionString", "database", "disk"}
|
fieldsInOrder := [...]string{"_and", "_not", "_or", "enabled", "majorVersion", "connectionString", "disk", "encryptColumnKey", "database", "oldEncryptColumnKey"}
|
||||||
for _, k := range fieldsInOrder {
|
for _, k := range fieldsInOrder {
|
||||||
v, ok := asMap[k]
|
v, ok := asMap[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -41067,13 +41183,6 @@ func (ec *executionContext) unmarshalInputConfigSystemConfigPostgresComparisonEx
|
|||||||
return it, err
|
return it, err
|
||||||
}
|
}
|
||||||
it.ConnectionString = data
|
it.ConnectionString = data
|
||||||
case "database":
|
|
||||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("database"))
|
|
||||||
data, err := ec.unmarshalOConfigStringComparisonExp2ᚖgithubᚗcomᚋnhostᚋbeᚋservicesᚋmimirᚋmodelᚐGenericComparisonExp(ctx, v)
|
|
||||||
if err != nil {
|
|
||||||
return it, err
|
|
||||||
}
|
|
||||||
it.Database = data
|
|
||||||
case "disk":
|
case "disk":
|
||||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("disk"))
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("disk"))
|
||||||
data, err := ec.unmarshalOConfigSystemConfigPostgresDiskComparisonExp2ᚖgithubᚗcomᚋnhostᚋbeᚋservicesᚋmimirᚋmodelᚐConfigSystemConfigPostgresDiskComparisonExp(ctx, v)
|
data, err := ec.unmarshalOConfigSystemConfigPostgresDiskComparisonExp2ᚖgithubᚗcomᚋnhostᚋbeᚋservicesᚋmimirᚋmodelᚐConfigSystemConfigPostgresDiskComparisonExp(ctx, v)
|
||||||
@@ -41081,6 +41190,27 @@ func (ec *executionContext) unmarshalInputConfigSystemConfigPostgresComparisonEx
|
|||||||
return it, err
|
return it, err
|
||||||
}
|
}
|
||||||
it.Disk = data
|
it.Disk = data
|
||||||
|
case "encryptColumnKey":
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("encryptColumnKey"))
|
||||||
|
data, err := ec.unmarshalOConfigStringComparisonExp2ᚖgithubᚗcomᚋnhostᚋbeᚋservicesᚋmimirᚋmodelᚐGenericComparisonExp(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.EncryptColumnKey = data
|
||||||
|
case "database":
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("database"))
|
||||||
|
data, err := ec.unmarshalOConfigStringComparisonExp2ᚖgithubᚗcomᚋnhostᚋbeᚋservicesᚋmimirᚋmodelᚐGenericComparisonExp(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.Database = data
|
||||||
|
case "oldEncryptColumnKey":
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("oldEncryptColumnKey"))
|
||||||
|
data, err := ec.unmarshalOConfigStringComparisonExp2ᚖgithubᚗcomᚋnhostᚋbeᚋservicesᚋmimirᚋmodelᚐGenericComparisonExp(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.OldEncryptColumnKey = data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41300,7 +41430,7 @@ func (ec *executionContext) unmarshalInputConfigSystemConfigPostgresInsertInput(
|
|||||||
asMap[k] = v
|
asMap[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldsInOrder := [...]string{"enabled", "majorVersion", "connectionString", "database", "disk"}
|
fieldsInOrder := [...]string{"enabled", "majorVersion", "connectionString", "disk", "encryptColumnKey", "database", "oldEncryptColumnKey"}
|
||||||
for _, k := range fieldsInOrder {
|
for _, k := range fieldsInOrder {
|
||||||
v, ok := asMap[k]
|
v, ok := asMap[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -41328,13 +41458,6 @@ func (ec *executionContext) unmarshalInputConfigSystemConfigPostgresInsertInput(
|
|||||||
return it, err
|
return it, err
|
||||||
}
|
}
|
||||||
it.ConnectionString = data
|
it.ConnectionString = data
|
||||||
case "database":
|
|
||||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("database"))
|
|
||||||
data, err := ec.unmarshalNString2string(ctx, v)
|
|
||||||
if err != nil {
|
|
||||||
return it, err
|
|
||||||
}
|
|
||||||
it.Database = data
|
|
||||||
case "disk":
|
case "disk":
|
||||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("disk"))
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("disk"))
|
||||||
data, err := ec.unmarshalOConfigSystemConfigPostgresDiskInsertInput2ᚖgithubᚗcomᚋnhostᚋbeᚋservicesᚋmimirᚋmodelᚐConfigSystemConfigPostgresDiskInsertInput(ctx, v)
|
data, err := ec.unmarshalOConfigSystemConfigPostgresDiskInsertInput2ᚖgithubᚗcomᚋnhostᚋbeᚋservicesᚋmimirᚋmodelᚐConfigSystemConfigPostgresDiskInsertInput(ctx, v)
|
||||||
@@ -41342,6 +41465,27 @@ func (ec *executionContext) unmarshalInputConfigSystemConfigPostgresInsertInput(
|
|||||||
return it, err
|
return it, err
|
||||||
}
|
}
|
||||||
it.Disk = data
|
it.Disk = data
|
||||||
|
case "encryptColumnKey":
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("encryptColumnKey"))
|
||||||
|
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.EncryptColumnKey = data
|
||||||
|
case "database":
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("database"))
|
||||||
|
data, err := ec.unmarshalNString2string(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.Database = data
|
||||||
|
case "oldEncryptColumnKey":
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("oldEncryptColumnKey"))
|
||||||
|
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.OldEncryptColumnKey = data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46042,13 +46186,17 @@ func (ec *executionContext) _ConfigSystemConfigPostgres(ctx context.Context, sel
|
|||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
out.Invalids++
|
out.Invalids++
|
||||||
}
|
}
|
||||||
|
case "disk":
|
||||||
|
out.Values[i] = ec._ConfigSystemConfigPostgres_disk(ctx, field, obj)
|
||||||
|
case "encryptColumnKey":
|
||||||
|
out.Values[i] = ec._ConfigSystemConfigPostgres_encryptColumnKey(ctx, field, obj)
|
||||||
case "database":
|
case "database":
|
||||||
out.Values[i] = ec._ConfigSystemConfigPostgres_database(ctx, field, obj)
|
out.Values[i] = ec._ConfigSystemConfigPostgres_database(ctx, field, obj)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
out.Invalids++
|
out.Invalids++
|
||||||
}
|
}
|
||||||
case "disk":
|
case "oldEncryptColumnKey":
|
||||||
out.Values[i] = ec._ConfigSystemConfigPostgres_disk(ctx, field, obj)
|
out.Values[i] = ec._ConfigSystemConfigPostgres_oldEncryptColumnKey(ctx, field, obj)
|
||||||
default:
|
default:
|
||||||
panic("unknown field " + strconv.Quote(field.Name))
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
}
|
}
|
||||||
|
|||||||
214
vendor/github.com/nhost/be/services/mimir/model/cuegraph_gen.go
generated
vendored
214
vendor/github.com/nhost/be/services/mimir/model/cuegraph_gen.go
generated
vendored
@@ -27181,9 +27181,13 @@ type ConfigSystemConfigPostgres struct {
|
|||||||
|
|
||||||
ConnectionString *ConfigSystemConfigPostgresConnectionString `json:"connectionString,omitempty" toml:"connectionString,omitempty"`
|
ConnectionString *ConfigSystemConfigPostgresConnectionString `json:"connectionString,omitempty" toml:"connectionString,omitempty"`
|
||||||
|
|
||||||
|
Disk *ConfigSystemConfigPostgresDisk `json:"disk,omitempty" toml:"disk,omitempty"`
|
||||||
|
|
||||||
|
EncryptColumnKey *string `json:"encryptColumnKey" toml:"encryptColumnKey"`
|
||||||
|
|
||||||
Database string `json:"database" toml:"database"`
|
Database string `json:"database" toml:"database"`
|
||||||
|
|
||||||
Disk *ConfigSystemConfigPostgresDisk `json:"disk,omitempty" toml:"disk,omitempty"`
|
OldEncryptColumnKey *string `json:"oldEncryptColumnKey" toml:"oldEncryptColumnKey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ConfigSystemConfigPostgres) MarshalJSON() ([]byte, error) {
|
func (o *ConfigSystemConfigPostgres) MarshalJSON() ([]byte, error) {
|
||||||
@@ -27197,10 +27201,16 @@ func (o *ConfigSystemConfigPostgres) MarshalJSON() ([]byte, error) {
|
|||||||
if o.ConnectionString != nil {
|
if o.ConnectionString != nil {
|
||||||
m["connectionString"] = o.ConnectionString
|
m["connectionString"] = o.ConnectionString
|
||||||
}
|
}
|
||||||
m["database"] = o.Database
|
|
||||||
if o.Disk != nil {
|
if o.Disk != nil {
|
||||||
m["disk"] = o.Disk
|
m["disk"] = o.Disk
|
||||||
}
|
}
|
||||||
|
if o.EncryptColumnKey != nil {
|
||||||
|
m["encryptColumnKey"] = o.EncryptColumnKey
|
||||||
|
}
|
||||||
|
m["database"] = o.Database
|
||||||
|
if o.OldEncryptColumnKey != nil {
|
||||||
|
m["oldEncryptColumnKey"] = o.OldEncryptColumnKey
|
||||||
|
}
|
||||||
return json.Marshal(m)
|
return json.Marshal(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27225,13 +27235,6 @@ func (o *ConfigSystemConfigPostgres) GetConnectionString() *ConfigSystemConfigPo
|
|||||||
return o.ConnectionString
|
return o.ConnectionString
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ConfigSystemConfigPostgres) GetDatabase() string {
|
|
||||||
if o == nil {
|
|
||||||
o = &ConfigSystemConfigPostgres{}
|
|
||||||
}
|
|
||||||
return o.Database
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *ConfigSystemConfigPostgres) GetDisk() *ConfigSystemConfigPostgresDisk {
|
func (o *ConfigSystemConfigPostgres) GetDisk() *ConfigSystemConfigPostgresDisk {
|
||||||
if o == nil {
|
if o == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -27239,17 +27242,42 @@ func (o *ConfigSystemConfigPostgres) GetDisk() *ConfigSystemConfigPostgresDisk {
|
|||||||
return o.Disk
|
return o.Disk
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *ConfigSystemConfigPostgres) GetEncryptColumnKey() *string {
|
||||||
|
if o == nil {
|
||||||
|
o = &ConfigSystemConfigPostgres{}
|
||||||
|
}
|
||||||
|
return o.EncryptColumnKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ConfigSystemConfigPostgres) GetDatabase() string {
|
||||||
|
if o == nil {
|
||||||
|
o = &ConfigSystemConfigPostgres{}
|
||||||
|
}
|
||||||
|
return o.Database
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ConfigSystemConfigPostgres) GetOldEncryptColumnKey() *string {
|
||||||
|
if o == nil {
|
||||||
|
o = &ConfigSystemConfigPostgres{}
|
||||||
|
}
|
||||||
|
return o.OldEncryptColumnKey
|
||||||
|
}
|
||||||
|
|
||||||
type ConfigSystemConfigPostgresUpdateInput struct {
|
type ConfigSystemConfigPostgresUpdateInput struct {
|
||||||
Enabled *bool `json:"enabled,omitempty" toml:"enabled,omitempty"`
|
Enabled *bool `json:"enabled,omitempty" toml:"enabled,omitempty"`
|
||||||
IsSetEnabled bool `json:"-"`
|
IsSetEnabled bool `json:"-"`
|
||||||
MajorVersion *string `json:"majorVersion,omitempty" toml:"majorVersion,omitempty"`
|
MajorVersion *string `json:"majorVersion,omitempty" toml:"majorVersion,omitempty"`
|
||||||
IsSetMajorVersion bool `json:"-"`
|
IsSetMajorVersion bool `json:"-"`
|
||||||
ConnectionString *ConfigSystemConfigPostgresConnectionStringUpdateInput `json:"connectionString,omitempty" toml:"connectionString,omitempty"`
|
ConnectionString *ConfigSystemConfigPostgresConnectionStringUpdateInput `json:"connectionString,omitempty" toml:"connectionString,omitempty"`
|
||||||
IsSetConnectionString bool `json:"-"`
|
IsSetConnectionString bool `json:"-"`
|
||||||
Database *string `json:"database,omitempty" toml:"database,omitempty"`
|
Disk *ConfigSystemConfigPostgresDiskUpdateInput `json:"disk,omitempty" toml:"disk,omitempty"`
|
||||||
IsSetDatabase bool `json:"-"`
|
IsSetDisk bool `json:"-"`
|
||||||
Disk *ConfigSystemConfigPostgresDiskUpdateInput `json:"disk,omitempty" toml:"disk,omitempty"`
|
EncryptColumnKey *string `json:"encryptColumnKey,omitempty" toml:"encryptColumnKey,omitempty"`
|
||||||
IsSetDisk bool `json:"-"`
|
IsSetEncryptColumnKey bool `json:"-"`
|
||||||
|
Database *string `json:"database,omitempty" toml:"database,omitempty"`
|
||||||
|
IsSetDatabase bool `json:"-"`
|
||||||
|
OldEncryptColumnKey *string `json:"oldEncryptColumnKey,omitempty" toml:"oldEncryptColumnKey,omitempty"`
|
||||||
|
IsSetOldEncryptColumnKey bool `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ConfigSystemConfigPostgresUpdateInput) UnmarshalGQL(v interface{}) error {
|
func (o *ConfigSystemConfigPostgresUpdateInput) UnmarshalGQL(v interface{}) error {
|
||||||
@@ -27301,6 +27329,33 @@ func (o *ConfigSystemConfigPostgresUpdateInput) UnmarshalGQL(v interface{}) erro
|
|||||||
}
|
}
|
||||||
o.IsSetConnectionString = true
|
o.IsSetConnectionString = true
|
||||||
}
|
}
|
||||||
|
if x, ok := m["disk"]; ok {
|
||||||
|
if x != nil {
|
||||||
|
t := &ConfigSystemConfigPostgresDiskUpdateInput{}
|
||||||
|
if err := t.UnmarshalGQL(x); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
o.Disk = t
|
||||||
|
}
|
||||||
|
o.IsSetDisk = true
|
||||||
|
}
|
||||||
|
if v, ok := m["encryptColumnKey"]; ok {
|
||||||
|
if v == nil {
|
||||||
|
o.EncryptColumnKey = nil
|
||||||
|
} else {
|
||||||
|
// clearly a not very efficient shortcut
|
||||||
|
b, err := json.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var x string
|
||||||
|
if err := json.Unmarshal(b, &x); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
o.EncryptColumnKey = &x
|
||||||
|
}
|
||||||
|
o.IsSetEncryptColumnKey = true
|
||||||
|
}
|
||||||
if v, ok := m["database"]; ok {
|
if v, ok := m["database"]; ok {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
o.Database = nil
|
o.Database = nil
|
||||||
@@ -27318,15 +27373,22 @@ func (o *ConfigSystemConfigPostgresUpdateInput) UnmarshalGQL(v interface{}) erro
|
|||||||
}
|
}
|
||||||
o.IsSetDatabase = true
|
o.IsSetDatabase = true
|
||||||
}
|
}
|
||||||
if x, ok := m["disk"]; ok {
|
if v, ok := m["oldEncryptColumnKey"]; ok {
|
||||||
if x != nil {
|
if v == nil {
|
||||||
t := &ConfigSystemConfigPostgresDiskUpdateInput{}
|
o.OldEncryptColumnKey = nil
|
||||||
if err := t.UnmarshalGQL(x); err != nil {
|
} else {
|
||||||
|
// clearly a not very efficient shortcut
|
||||||
|
b, err := json.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
o.Disk = t
|
var x string
|
||||||
|
if err := json.Unmarshal(b, &x); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
o.OldEncryptColumnKey = &x
|
||||||
}
|
}
|
||||||
o.IsSetDisk = true
|
o.IsSetOldEncryptColumnKey = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -27360,6 +27422,20 @@ func (o *ConfigSystemConfigPostgresUpdateInput) GetConnectionString() *ConfigSys
|
|||||||
return o.ConnectionString
|
return o.ConnectionString
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *ConfigSystemConfigPostgresUpdateInput) GetDisk() *ConfigSystemConfigPostgresDiskUpdateInput {
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return o.Disk
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ConfigSystemConfigPostgresUpdateInput) GetEncryptColumnKey() *string {
|
||||||
|
if o == nil {
|
||||||
|
o = &ConfigSystemConfigPostgresUpdateInput{}
|
||||||
|
}
|
||||||
|
return o.EncryptColumnKey
|
||||||
|
}
|
||||||
|
|
||||||
func (o *ConfigSystemConfigPostgresUpdateInput) GetDatabase() *string {
|
func (o *ConfigSystemConfigPostgresUpdateInput) GetDatabase() *string {
|
||||||
if o == nil {
|
if o == nil {
|
||||||
o = &ConfigSystemConfigPostgresUpdateInput{}
|
o = &ConfigSystemConfigPostgresUpdateInput{}
|
||||||
@@ -27367,11 +27443,11 @@ func (o *ConfigSystemConfigPostgresUpdateInput) GetDatabase() *string {
|
|||||||
return o.Database
|
return o.Database
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ConfigSystemConfigPostgresUpdateInput) GetDisk() *ConfigSystemConfigPostgresDiskUpdateInput {
|
func (o *ConfigSystemConfigPostgresUpdateInput) GetOldEncryptColumnKey() *string {
|
||||||
if o == nil {
|
if o == nil {
|
||||||
return nil
|
o = &ConfigSystemConfigPostgresUpdateInput{}
|
||||||
}
|
}
|
||||||
return o.Disk
|
return o.OldEncryptColumnKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ConfigSystemConfigPostgres) Update(v *ConfigSystemConfigPostgresUpdateInput) {
|
func (s *ConfigSystemConfigPostgres) Update(v *ConfigSystemConfigPostgresUpdateInput) {
|
||||||
@@ -27394,11 +27470,6 @@ func (s *ConfigSystemConfigPostgres) Update(v *ConfigSystemConfigPostgresUpdateI
|
|||||||
s.ConnectionString.Update(v.ConnectionString)
|
s.ConnectionString.Update(v.ConnectionString)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if v.IsSetDatabase || v.Database != nil {
|
|
||||||
if v.Database != nil {
|
|
||||||
s.Database = *v.Database
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if v.IsSetDisk || v.Disk != nil {
|
if v.IsSetDisk || v.Disk != nil {
|
||||||
if v.Disk == nil {
|
if v.Disk == nil {
|
||||||
s.Disk = nil
|
s.Disk = nil
|
||||||
@@ -27409,14 +27480,27 @@ func (s *ConfigSystemConfigPostgres) Update(v *ConfigSystemConfigPostgresUpdateI
|
|||||||
s.Disk.Update(v.Disk)
|
s.Disk.Update(v.Disk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if v.IsSetEncryptColumnKey || v.EncryptColumnKey != nil {
|
||||||
|
s.EncryptColumnKey = v.EncryptColumnKey
|
||||||
|
}
|
||||||
|
if v.IsSetDatabase || v.Database != nil {
|
||||||
|
if v.Database != nil {
|
||||||
|
s.Database = *v.Database
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v.IsSetOldEncryptColumnKey || v.OldEncryptColumnKey != nil {
|
||||||
|
s.OldEncryptColumnKey = v.OldEncryptColumnKey
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigSystemConfigPostgresInsertInput struct {
|
type ConfigSystemConfigPostgresInsertInput struct {
|
||||||
Enabled *bool `json:"enabled,omitempty" toml:"enabled,omitempty"`
|
Enabled *bool `json:"enabled,omitempty" toml:"enabled,omitempty"`
|
||||||
MajorVersion *string `json:"majorVersion,omitempty" toml:"majorVersion,omitempty"`
|
MajorVersion *string `json:"majorVersion,omitempty" toml:"majorVersion,omitempty"`
|
||||||
ConnectionString *ConfigSystemConfigPostgresConnectionStringInsertInput `json:"connectionString,omitempty" toml:"connectionString,omitempty"`
|
ConnectionString *ConfigSystemConfigPostgresConnectionStringInsertInput `json:"connectionString,omitempty" toml:"connectionString,omitempty"`
|
||||||
Database string `json:"database,omitempty" toml:"database,omitempty"`
|
Disk *ConfigSystemConfigPostgresDiskInsertInput `json:"disk,omitempty" toml:"disk,omitempty"`
|
||||||
Disk *ConfigSystemConfigPostgresDiskInsertInput `json:"disk,omitempty" toml:"disk,omitempty"`
|
EncryptColumnKey *string `json:"encryptColumnKey,omitempty" toml:"encryptColumnKey,omitempty"`
|
||||||
|
Database string `json:"database,omitempty" toml:"database,omitempty"`
|
||||||
|
OldEncryptColumnKey *string `json:"oldEncryptColumnKey,omitempty" toml:"oldEncryptColumnKey,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ConfigSystemConfigPostgresInsertInput) GetEnabled() *bool {
|
func (o *ConfigSystemConfigPostgresInsertInput) GetEnabled() *bool {
|
||||||
@@ -27440,6 +27524,20 @@ func (o *ConfigSystemConfigPostgresInsertInput) GetConnectionString() *ConfigSys
|
|||||||
return o.ConnectionString
|
return o.ConnectionString
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *ConfigSystemConfigPostgresInsertInput) GetDisk() *ConfigSystemConfigPostgresDiskInsertInput {
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return o.Disk
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ConfigSystemConfigPostgresInsertInput) GetEncryptColumnKey() *string {
|
||||||
|
if o == nil {
|
||||||
|
o = &ConfigSystemConfigPostgresInsertInput{}
|
||||||
|
}
|
||||||
|
return o.EncryptColumnKey
|
||||||
|
}
|
||||||
|
|
||||||
func (o *ConfigSystemConfigPostgresInsertInput) GetDatabase() string {
|
func (o *ConfigSystemConfigPostgresInsertInput) GetDatabase() string {
|
||||||
if o == nil {
|
if o == nil {
|
||||||
o = &ConfigSystemConfigPostgresInsertInput{}
|
o = &ConfigSystemConfigPostgresInsertInput{}
|
||||||
@@ -27447,11 +27545,11 @@ func (o *ConfigSystemConfigPostgresInsertInput) GetDatabase() string {
|
|||||||
return o.Database
|
return o.Database
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ConfigSystemConfigPostgresInsertInput) GetDisk() *ConfigSystemConfigPostgresDiskInsertInput {
|
func (o *ConfigSystemConfigPostgresInsertInput) GetOldEncryptColumnKey() *string {
|
||||||
if o == nil {
|
if o == nil {
|
||||||
return nil
|
o = &ConfigSystemConfigPostgresInsertInput{}
|
||||||
}
|
}
|
||||||
return o.Disk
|
return o.OldEncryptColumnKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ConfigSystemConfigPostgres) Insert(v *ConfigSystemConfigPostgresInsertInput) {
|
func (s *ConfigSystemConfigPostgres) Insert(v *ConfigSystemConfigPostgresInsertInput) {
|
||||||
@@ -27463,13 +27561,15 @@ func (s *ConfigSystemConfigPostgres) Insert(v *ConfigSystemConfigPostgresInsertI
|
|||||||
}
|
}
|
||||||
s.ConnectionString.Insert(v.ConnectionString)
|
s.ConnectionString.Insert(v.ConnectionString)
|
||||||
}
|
}
|
||||||
s.Database = v.Database
|
|
||||||
if v.Disk != nil {
|
if v.Disk != nil {
|
||||||
if s.Disk == nil {
|
if s.Disk == nil {
|
||||||
s.Disk = &ConfigSystemConfigPostgresDisk{}
|
s.Disk = &ConfigSystemConfigPostgresDisk{}
|
||||||
}
|
}
|
||||||
s.Disk.Insert(v.Disk)
|
s.Disk.Insert(v.Disk)
|
||||||
}
|
}
|
||||||
|
s.EncryptColumnKey = v.EncryptColumnKey
|
||||||
|
s.Database = v.Database
|
||||||
|
s.OldEncryptColumnKey = v.OldEncryptColumnKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ConfigSystemConfigPostgres) Clone() *ConfigSystemConfigPostgres {
|
func (s *ConfigSystemConfigPostgres) Clone() *ConfigSystemConfigPostgres {
|
||||||
@@ -27481,20 +27581,24 @@ func (s *ConfigSystemConfigPostgres) Clone() *ConfigSystemConfigPostgres {
|
|||||||
v.Enabled = s.Enabled
|
v.Enabled = s.Enabled
|
||||||
v.MajorVersion = s.MajorVersion
|
v.MajorVersion = s.MajorVersion
|
||||||
v.ConnectionString = s.ConnectionString.Clone()
|
v.ConnectionString = s.ConnectionString.Clone()
|
||||||
v.Database = s.Database
|
|
||||||
v.Disk = s.Disk.Clone()
|
v.Disk = s.Disk.Clone()
|
||||||
|
v.EncryptColumnKey = s.EncryptColumnKey
|
||||||
|
v.Database = s.Database
|
||||||
|
v.OldEncryptColumnKey = s.OldEncryptColumnKey
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigSystemConfigPostgresComparisonExp struct {
|
type ConfigSystemConfigPostgresComparisonExp struct {
|
||||||
And []*ConfigSystemConfigPostgresComparisonExp `json:"_and,omitempty"`
|
And []*ConfigSystemConfigPostgresComparisonExp `json:"_and,omitempty"`
|
||||||
Not *ConfigSystemConfigPostgresComparisonExp `json:"_not,omitempty"`
|
Not *ConfigSystemConfigPostgresComparisonExp `json:"_not,omitempty"`
|
||||||
Or []*ConfigSystemConfigPostgresComparisonExp `json:"_or,omitempty"`
|
Or []*ConfigSystemConfigPostgresComparisonExp `json:"_or,omitempty"`
|
||||||
Enabled *ConfigBooleanComparisonExp `json:"enabled,omitempty"`
|
Enabled *ConfigBooleanComparisonExp `json:"enabled,omitempty"`
|
||||||
MajorVersion *ConfigStringComparisonExp `json:"majorVersion,omitempty"`
|
MajorVersion *ConfigStringComparisonExp `json:"majorVersion,omitempty"`
|
||||||
ConnectionString *ConfigSystemConfigPostgresConnectionStringComparisonExp `json:"connectionString,omitempty"`
|
ConnectionString *ConfigSystemConfigPostgresConnectionStringComparisonExp `json:"connectionString,omitempty"`
|
||||||
Database *ConfigStringComparisonExp `json:"database,omitempty"`
|
Disk *ConfigSystemConfigPostgresDiskComparisonExp `json:"disk,omitempty"`
|
||||||
Disk *ConfigSystemConfigPostgresDiskComparisonExp `json:"disk,omitempty"`
|
EncryptColumnKey *ConfigStringComparisonExp `json:"encryptColumnKey,omitempty"`
|
||||||
|
Database *ConfigStringComparisonExp `json:"database,omitempty"`
|
||||||
|
OldEncryptColumnKey *ConfigStringComparisonExp `json:"oldEncryptColumnKey,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (exp *ConfigSystemConfigPostgresComparisonExp) Matches(o *ConfigSystemConfigPostgres) bool {
|
func (exp *ConfigSystemConfigPostgresComparisonExp) Matches(o *ConfigSystemConfigPostgres) bool {
|
||||||
@@ -27517,10 +27621,16 @@ func (exp *ConfigSystemConfigPostgresComparisonExp) Matches(o *ConfigSystemConfi
|
|||||||
if !exp.ConnectionString.Matches(o.ConnectionString) {
|
if !exp.ConnectionString.Matches(o.ConnectionString) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if !exp.Disk.Matches(o.Disk) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if o.EncryptColumnKey != nil && !exp.EncryptColumnKey.Matches(*o.EncryptColumnKey) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if !exp.Database.Matches(o.Database) {
|
if !exp.Database.Matches(o.Database) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !exp.Disk.Matches(o.Disk) {
|
if o.OldEncryptColumnKey != nil && !exp.OldEncryptColumnKey.Matches(*o.OldEncryptColumnKey) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
8
vendor/github.com/nhost/be/services/mimir/schema/appconfig/hasura_auth.go
generated
vendored
8
vendor/github.com/nhost/be/services/mimir/schema/appconfig/hasura_auth.go
generated
vendored
@@ -14,6 +14,7 @@ const (
|
|||||||
secretHasuraAuthHasuraAdminSecret = "adminSecret"
|
secretHasuraAuthHasuraAdminSecret = "adminSecret"
|
||||||
secretHasuraAuthJWTSecret = "jwtSecret"
|
secretHasuraAuthJWTSecret = "jwtSecret"
|
||||||
secretHasuraAuthSMTPPassword = "smtpPassword"
|
secretHasuraAuthSMTPPassword = "smtpPassword"
|
||||||
|
secretHasuraAuthEncryptionKey = "encryptionKey"
|
||||||
)
|
)
|
||||||
|
|
||||||
type oauthsettings interface {
|
type oauthsettings interface {
|
||||||
@@ -85,6 +86,7 @@ func HasuraAuthEnv( //nolint:funlen,cyclop,maintidx,gocyclo,gocognit
|
|||||||
isCustomSMTP bool,
|
isCustomSMTP bool,
|
||||||
autoScalerEnabled bool,
|
autoScalerEnabled bool,
|
||||||
appID string,
|
appID string,
|
||||||
|
encryptionKey string,
|
||||||
) ([]EnvVar, error) {
|
) ([]EnvVar, error) {
|
||||||
customClaims := make(
|
customClaims := make(
|
||||||
map[string]string,
|
map[string]string,
|
||||||
@@ -162,6 +164,12 @@ func HasuraAuthEnv( //nolint:funlen,cyclop,maintidx,gocyclo,gocognit
|
|||||||
IsSecret: false,
|
IsSecret: false,
|
||||||
SecretName: "",
|
SecretName: "",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "AUTH_ENCRYPTION_KEY",
|
||||||
|
SecretName: secretHasuraAuthEncryptionKey,
|
||||||
|
Value: encryptionKey,
|
||||||
|
IsSecret: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "AUTH_ACCESS_TOKEN_EXPIRES_IN",
|
Name: "AUTH_ACCESS_TOKEN_EXPIRES_IN",
|
||||||
Value: Stringify(
|
Value: Stringify(
|
||||||
|
|||||||
9
vendor/github.com/nhost/be/services/mimir/schema/schema.cue
generated
vendored
9
vendor/github.com/nhost/be/services/mimir/schema/schema.cue
generated
vendored
@@ -148,7 +148,7 @@ import (
|
|||||||
#Hasura: {
|
#Hasura: {
|
||||||
// Version of hasura, you can see available versions in the URL below:
|
// Version of hasura, you can see available versions in the URL below:
|
||||||
// https://hub.docker.com/r/hasura/graphql-engine/tags
|
// https://hub.docker.com/r/hasura/graphql-engine/tags
|
||||||
version: string | *"v2.46.0-ce"
|
version: string | *"v2.48.5-ce"
|
||||||
|
|
||||||
// JWT Secrets configuration
|
// JWT Secrets configuration
|
||||||
jwtSecrets: [#JWTSecret]
|
jwtSecrets: [#JWTSecret]
|
||||||
@@ -223,7 +223,7 @@ import (
|
|||||||
// Releases:
|
// Releases:
|
||||||
//
|
//
|
||||||
// https://github.com/nhost/hasura-storage/releases
|
// https://github.com/nhost/hasura-storage/releases
|
||||||
version: string | *"0.7.2"
|
version: string | *"0.8.2"
|
||||||
|
|
||||||
// Networking (custom domains at the moment) are not allowed as we need to do further
|
// Networking (custom domains at the moment) are not allowed as we need to do further
|
||||||
// configurations in the CDN. We will enable it again in the future.
|
// configurations in the CDN. We will enable it again in the future.
|
||||||
@@ -311,7 +311,7 @@ import (
|
|||||||
// Releases:
|
// Releases:
|
||||||
//
|
//
|
||||||
// https://github.com/nhost/hasura-auth/releases
|
// https://github.com/nhost/hasura-auth/releases
|
||||||
version: string | *"0.38.1"
|
version: string | *"0.42.4"
|
||||||
|
|
||||||
// Resources for the service
|
// Resources for the service
|
||||||
resources?: #Resources
|
resources?: #Resources
|
||||||
@@ -651,6 +651,9 @@ import (
|
|||||||
iops: uint32 | *3000
|
iops: uint32 | *3000
|
||||||
tput: uint32 | *125
|
tput: uint32 | *125
|
||||||
}
|
}
|
||||||
|
|
||||||
|
encryptColumnKey?: string & =~"^[0-9a-fA-F]{64}$" // 32 bytes hex-encoded key
|
||||||
|
oldEncryptColumnKey?: string & =~"^[0-9a-fA-F]{64}$" // for key rotation
|
||||||
}
|
}
|
||||||
|
|
||||||
persistentVolumesEncrypted: bool | *false
|
persistentVolumesEncrypted: bool | *false
|
||||||
|
|||||||
22
vendor/github.com/nhost/be/services/mimir/schema/schema_gen.graphqls
generated
vendored
22
vendor/github.com/nhost/be/services/mimir/schema/schema_gen.graphqls
generated
vendored
@@ -4193,28 +4193,40 @@ type ConfigSystemConfigPostgres {
|
|||||||
connectionString: ConfigSystemConfigPostgresConnectionString!
|
connectionString: ConfigSystemConfigPostgresConnectionString!
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
disk: ConfigSystemConfigPostgresDisk
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
encryptColumnKey: String
|
||||||
|
"""
|
||||||
|
|
||||||
"""
|
"""
|
||||||
database: String!
|
database: String!
|
||||||
"""
|
"""
|
||||||
|
|
||||||
"""
|
"""
|
||||||
disk: ConfigSystemConfigPostgresDisk
|
oldEncryptColumnKey: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input ConfigSystemConfigPostgresUpdateInput {
|
input ConfigSystemConfigPostgresUpdateInput {
|
||||||
enabled: Boolean
|
enabled: Boolean
|
||||||
majorVersion: String
|
majorVersion: String
|
||||||
connectionString: ConfigSystemConfigPostgresConnectionStringUpdateInput
|
connectionString: ConfigSystemConfigPostgresConnectionStringUpdateInput
|
||||||
database: String
|
|
||||||
disk: ConfigSystemConfigPostgresDiskUpdateInput
|
disk: ConfigSystemConfigPostgresDiskUpdateInput
|
||||||
|
encryptColumnKey: String
|
||||||
|
database: String
|
||||||
|
oldEncryptColumnKey: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input ConfigSystemConfigPostgresInsertInput {
|
input ConfigSystemConfigPostgresInsertInput {
|
||||||
enabled: Boolean
|
enabled: Boolean
|
||||||
majorVersion: String
|
majorVersion: String
|
||||||
connectionString: ConfigSystemConfigPostgresConnectionStringInsertInput!
|
connectionString: ConfigSystemConfigPostgresConnectionStringInsertInput!
|
||||||
database: String!
|
|
||||||
disk: ConfigSystemConfigPostgresDiskInsertInput
|
disk: ConfigSystemConfigPostgresDiskInsertInput
|
||||||
|
encryptColumnKey: String
|
||||||
|
database: String!
|
||||||
|
oldEncryptColumnKey: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input ConfigSystemConfigPostgresComparisonExp {
|
input ConfigSystemConfigPostgresComparisonExp {
|
||||||
@@ -4224,8 +4236,10 @@ input ConfigSystemConfigPostgresComparisonExp {
|
|||||||
enabled: ConfigBooleanComparisonExp
|
enabled: ConfigBooleanComparisonExp
|
||||||
majorVersion: ConfigStringComparisonExp
|
majorVersion: ConfigStringComparisonExp
|
||||||
connectionString: ConfigSystemConfigPostgresConnectionStringComparisonExp
|
connectionString: ConfigSystemConfigPostgresConnectionStringComparisonExp
|
||||||
database: ConfigStringComparisonExp
|
|
||||||
disk: ConfigSystemConfigPostgresDiskComparisonExp
|
disk: ConfigSystemConfigPostgresDiskComparisonExp
|
||||||
|
encryptColumnKey: ConfigStringComparisonExp
|
||||||
|
database: ConfigStringComparisonExp
|
||||||
|
oldEncryptColumnKey: ConfigStringComparisonExp
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|||||||
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@@ -719,7 +719,7 @@ github.com/muesli/termenv
|
|||||||
# github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
|
# github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
|
||||||
## explicit
|
## explicit
|
||||||
github.com/munnerz/goautoneg
|
github.com/munnerz/goautoneg
|
||||||
# github.com/nhost/be v0.0.0-20250929153845-6db3e5249d33
|
# github.com/nhost/be v0.0.0-20251021065906-8abc7d8dfa48
|
||||||
## explicit; go 1.24.2
|
## explicit; go 1.24.2
|
||||||
github.com/nhost/be/lib/graphql
|
github.com/nhost/be/lib/graphql
|
||||||
github.com/nhost/be/lib/graphql/context
|
github.com/nhost/be/lib/graphql/context
|
||||||
|
|||||||
Reference in New Issue
Block a user