mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-02-23 21:44:07 +00:00
Compare commits
3 Commits
chore/depo
...
v2.3.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
375f0a0c34 | ||
|
|
522a4eee00 | ||
|
|
0c41872cd4 |
41
CHANGELOG.md
41
CHANGELOG.md
@@ -1,3 +1,44 @@
|
||||
## v2.3.0
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- ENCRYPTION_KEY needed for version and help commands ([#1256](https://github.com/pocket-id/pocket-id/pull/1256) by @kmendell)
|
||||
- prevent deletion of OIDC provider logo for non admin/anonymous users ([#1267](https://github.com/pocket-id/pocket-id/pull/1267) by @HiMoritz)
|
||||
- add `type="url"` to url inputs ([bb7b0d5](https://github.com/pocket-id/pocket-id/commit/bb7b0d56084df49b6a003cc3eaf076884e2cbf60) by @stonith404)
|
||||
- increase rate limit for frontend and api requests ([aab7e36](https://github.com/pocket-id/pocket-id/commit/aab7e364e85f1ce13950da93cc50324328cdd96d) by @stonith404)
|
||||
- decode URL-encoded client ID and secret in Basic auth ([#1263](https://github.com/pocket-id/pocket-id/pull/1263) by @ypomortsev)
|
||||
- token endpoint must not accept params as query string args ([#1321](https://github.com/pocket-id/pocket-id/pull/1321) by @ItalyPaleAle)
|
||||
- left align input error messages ([b3fe143](https://github.com/pocket-id/pocket-id/commit/b3fe14313684f9d8c389ed93ea8e479e3681b5c6) by @stonith404)
|
||||
- disallow API key renewal and creation with API key authentication ([#1334](https://github.com/pocket-id/pocket-id/pull/1334) by @stonith404)
|
||||
|
||||
### Features
|
||||
|
||||
- add VERSION_CHECK_DISABLED environment variable ([#1254](https://github.com/pocket-id/pocket-id/pull/1254) by @dihmandrake)
|
||||
- add support for HTTP/2 ([56afebc](https://github.com/pocket-id/pocket-id/commit/56afebc242be7ed14b58185425d6445bf18f640a) by @stonith404)
|
||||
- manageability of uncompressed geolite db file ([#1234](https://github.com/pocket-id/pocket-id/pull/1234) by @gucheen)
|
||||
- add JWT ID for generated tokens ([#1322](https://github.com/pocket-id/pocket-id/pull/1322) by @imnotjames)
|
||||
- current version api endpoint ([#1310](https://github.com/pocket-id/pocket-id/pull/1310) by @kmendell)
|
||||
|
||||
### Other
|
||||
|
||||
- bump @sveltejs/kit from 2.49.2 to 2.49.5 in the npm_and_yarn group across 1 directory ([#1240](https://github.com/pocket-id/pocket-id/pull/1240) by @dependabot[bot])
|
||||
- bump svelte from 5.46.1 to 5.46.4 in the npm_and_yarn group across 1 directory ([#1242](https://github.com/pocket-id/pocket-id/pull/1242) by @dependabot[bot])
|
||||
- bump devalue to 5.6.2 ([9dbc02e](https://github.com/pocket-id/pocket-id/commit/9dbc02e56871b2de6a39c443e1455efc26a949f7) by @kmendell)
|
||||
- upgrade deps ([4811625](https://github.com/pocket-id/pocket-id/commit/4811625cdd64b47ea67b7a9b03396e455896ccd6) by @kmendell)
|
||||
- add Estonian files ([53ef61a](https://github.com/pocket-id/pocket-id/commit/53ef61a3e5c4b77edec49d41ab94302bfec84269) by @kmendell)
|
||||
- update AAGUIDs ([#1257](https://github.com/pocket-id/pocket-id/pull/1257) by @github-actions[bot])
|
||||
- add Norwegian language files ([80558c5](https://github.com/pocket-id/pocket-id/commit/80558c562533e7b4d658d5baa4221d8cd209b47d) by @stonith404)
|
||||
- run formatter ([60825c5](https://github.com/pocket-id/pocket-id/commit/60825c5743b0e233ab622fd4d0ea04eb7ab59529) by @kmendell)
|
||||
- bump axios from 1.13.2 to 1.13.5 in the npm_and_yarn group across 1 directory ([#1309](https://github.com/pocket-id/pocket-id/pull/1309) by @dependabot[bot])
|
||||
- update dependenicies ([94a4897](https://github.com/pocket-id/pocket-id/commit/94a48977ba24e099b6221838d620c365eb1d4bf4) by @kmendell)
|
||||
- update AAGUIDs ([#1316](https://github.com/pocket-id/pocket-id/pull/1316) by @github-actions[bot])
|
||||
- bump svelte from 5.46.4 to 5.51.5 in the npm_and_yarn group across 1 directory ([#1324](https://github.com/pocket-id/pocket-id/pull/1324) by @dependabot[bot])
|
||||
- bump @sveltejs/kit from 2.49.5 to 2.52.2 in the npm_and_yarn group across 1 directory ([#1327](https://github.com/pocket-id/pocket-id/pull/1327) by @dependabot[bot])
|
||||
- upgrade dependencies ([0678699](https://github.com/pocket-id/pocket-id/commit/0678699d0cce5448c425b2c16bedab5fc242cbf0) by @stonith404)
|
||||
- upgrade to node 24 and go 1.26.0 ([#1328](https://github.com/pocket-id/pocket-id/pull/1328) by @kmendell)
|
||||
|
||||
**Full Changelog**: https://github.com/pocket-id/pocket-id/compare/v2.2.0...v2.3.0
|
||||
|
||||
## v2.2.0
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -280,6 +280,13 @@ func (e *APIKeyExpirationDateError) Error() string {
|
||||
}
|
||||
func (e *APIKeyExpirationDateError) HttpStatusCode() int { return http.StatusBadRequest }
|
||||
|
||||
type APIKeyAuthNotAllowedError struct{}
|
||||
|
||||
func (e *APIKeyAuthNotAllowedError) Error() string {
|
||||
return "API key authentication is not allowed for this endpoint"
|
||||
}
|
||||
func (e *APIKeyAuthNotAllowedError) HttpStatusCode() int { return http.StatusForbidden }
|
||||
|
||||
type OidcInvalidRefreshTokenError struct{}
|
||||
|
||||
func (e *OidcInvalidRefreshTokenError) Error() string {
|
||||
|
||||
@@ -26,12 +26,11 @@ func NewApiKeyController(group *gin.RouterGroup, authMiddleware *middleware.Auth
|
||||
uc := &ApiKeyController{apiKeyService: apiKeyService}
|
||||
|
||||
apiKeyGroup := group.Group("/api-keys")
|
||||
apiKeyGroup.Use(authMiddleware.WithAdminNotRequired().Add())
|
||||
{
|
||||
apiKeyGroup.GET("", uc.listApiKeysHandler)
|
||||
apiKeyGroup.POST("", uc.createApiKeyHandler)
|
||||
apiKeyGroup.POST("/:id/renew", uc.renewApiKeyHandler)
|
||||
apiKeyGroup.DELETE("/:id", uc.revokeApiKeyHandler)
|
||||
apiKeyGroup.GET("", authMiddleware.WithAdminNotRequired().Add(), uc.listApiKeysHandler)
|
||||
apiKeyGroup.POST("", authMiddleware.WithAdminNotRequired().WithApiKeyAuthDisabled().Add(), uc.createApiKeyHandler)
|
||||
apiKeyGroup.POST("/:id/renew", authMiddleware.WithAdminNotRequired().WithApiKeyAuthDisabled().Add(), uc.renewApiKeyHandler)
|
||||
apiKeyGroup.DELETE("/:id", authMiddleware.WithAdminNotRequired().Add(), uc.revokeApiKeyHandler)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ type AuthMiddleware struct {
|
||||
type AuthOptions struct {
|
||||
AdminRequired bool
|
||||
SuccessOptional bool
|
||||
AllowApiKeyAuth bool
|
||||
}
|
||||
|
||||
func NewAuthMiddleware(
|
||||
@@ -31,6 +32,7 @@ func NewAuthMiddleware(
|
||||
options: AuthOptions{
|
||||
AdminRequired: true,
|
||||
SuccessOptional: false,
|
||||
AllowApiKeyAuth: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -59,6 +61,17 @@ func (m *AuthMiddleware) WithSuccessOptional() *AuthMiddleware {
|
||||
return clone
|
||||
}
|
||||
|
||||
// WithApiKeyAuthDisabled disables API key authentication fallback and requires JWT auth.
|
||||
func (m *AuthMiddleware) WithApiKeyAuthDisabled() *AuthMiddleware {
|
||||
clone := &AuthMiddleware{
|
||||
apiKeyMiddleware: m.apiKeyMiddleware,
|
||||
jwtMiddleware: m.jwtMiddleware,
|
||||
options: m.options,
|
||||
}
|
||||
clone.options.AllowApiKeyAuth = false
|
||||
return clone
|
||||
}
|
||||
|
||||
func (m *AuthMiddleware) Add() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
userID, isAdmin, err := m.jwtMiddleware.Verify(c, m.options.AdminRequired)
|
||||
@@ -79,6 +92,21 @@ func (m *AuthMiddleware) Add() gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
if !m.options.AllowApiKeyAuth {
|
||||
if m.options.SuccessOptional {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
c.Abort()
|
||||
if c.GetHeader("X-API-Key") != "" {
|
||||
_ = c.Error(&common.APIKeyAuthNotAllowedError{})
|
||||
return
|
||||
}
|
||||
_ = c.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// JWT auth failed, try API key auth
|
||||
userID, isAdmin, err = m.apiKeyMiddleware.Verify(c, m.options.AdminRequired)
|
||||
if err == nil {
|
||||
|
||||
104
backend/internal/middleware/auth_middleware_test.go
Normal file
104
backend/internal/middleware/auth_middleware_test.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/pocket-id/pocket-id/backend/internal/common"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/dto"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/model"
|
||||
datatype "github.com/pocket-id/pocket-id/backend/internal/model/types"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/service"
|
||||
testutils "github.com/pocket-id/pocket-id/backend/internal/utils/testing"
|
||||
)
|
||||
|
||||
func TestWithApiKeyAuthDisabled(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
originalEnvConfig := common.EnvConfig
|
||||
defer func() {
|
||||
common.EnvConfig = originalEnvConfig
|
||||
}()
|
||||
common.EnvConfig.AppURL = "https://test.example.com"
|
||||
common.EnvConfig.EncryptionKey = []byte("0123456789abcdef0123456789abcdef")
|
||||
|
||||
db := testutils.NewDatabaseForTest(t)
|
||||
|
||||
appConfigService, err := service.NewAppConfigService(t.Context(), db)
|
||||
require.NoError(t, err)
|
||||
|
||||
jwtService, err := service.NewJwtService(t.Context(), db, appConfigService)
|
||||
require.NoError(t, err)
|
||||
|
||||
userService := service.NewUserService(db, jwtService, nil, nil, appConfigService, nil, nil, nil, nil)
|
||||
apiKeyService, err := service.NewApiKeyService(t.Context(), db, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
authMiddleware := NewAuthMiddleware(apiKeyService, userService, jwtService)
|
||||
|
||||
user := createUserForAuthMiddlewareTest(t, db)
|
||||
jwtToken, err := jwtService.GenerateAccessToken(user)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, apiKeyToken, err := apiKeyService.CreateApiKey(t.Context(), user.ID, dto.ApiKeyCreateDto{
|
||||
Name: "Middleware API Key",
|
||||
ExpiresAt: datatype.DateTime(time.Now().Add(24 * time.Hour)),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
router := gin.New()
|
||||
router.Use(NewErrorHandlerMiddleware().Add())
|
||||
router.GET("/api/protected", authMiddleware.WithAdminNotRequired().WithApiKeyAuthDisabled().Add(), func(c *gin.Context) {
|
||||
c.Status(http.StatusNoContent)
|
||||
})
|
||||
|
||||
t.Run("rejects API key auth when API key auth is disabled", func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/protected", nil)
|
||||
req.Header.Set("X-API-Key", apiKeyToken)
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(recorder, req)
|
||||
|
||||
require.Equal(t, http.StatusForbidden, recorder.Code)
|
||||
|
||||
var body map[string]string
|
||||
err := json.Unmarshal(recorder.Body.Bytes(), &body)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "API key authentication is not allowed for this endpoint", body["error"])
|
||||
})
|
||||
|
||||
t.Run("allows JWT auth when API key auth is disabled", func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/protected", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+jwtToken)
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(recorder, req)
|
||||
|
||||
require.Equal(t, http.StatusNoContent, recorder.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func createUserForAuthMiddlewareTest(t *testing.T, db *gorm.DB) model.User {
|
||||
t.Helper()
|
||||
|
||||
email := "auth@example.com"
|
||||
user := model.User{
|
||||
Username: "auth-user",
|
||||
Email: &email,
|
||||
FirstName: "Auth",
|
||||
LastName: "User",
|
||||
DisplayName: "Auth User",
|
||||
}
|
||||
|
||||
err := db.Create(&user).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
return user
|
||||
}
|
||||
@@ -77,6 +77,9 @@ func (s *ApiKeyService) CreateApiKey(ctx context.Context, userID string, input d
|
||||
Create(&apiKey).
|
||||
Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrDuplicatedKey) {
|
||||
return model.ApiKey{}, "", &common.AlreadyInUseError{Property: "API key name"}
|
||||
}
|
||||
return model.ApiKey{}, "", err
|
||||
}
|
||||
|
||||
|
||||
@@ -457,59 +457,59 @@
|
||||
"custom_client_id_description": "Встановіть власний ідентифікатор клієнта, якщо це вимагається вашим застосунком. В іншому випадку залиште поле порожнім, щоб згенерувати випадковий.",
|
||||
"generated": "Створено",
|
||||
"administration": "Адміністрування",
|
||||
"group_rdn_attribute_description": "Атрибут, що використовується в розрізнювальному імені групи (DN).",
|
||||
"group_rdn_attribute_description": "Атрибут, який використовується в DN (Distinguished Name) групи.",
|
||||
"display_name_attribute": "Атрибут імені для відображення",
|
||||
"display_name": "Ім'я для відображення",
|
||||
"configure_application_images": "Налаштування зображень застосунку",
|
||||
"ui_config_disabled_info_title": "Конфігурація інтерфейсу користувача вимкнена",
|
||||
"ui_config_disabled_info_description": "Конфігурація інтерфейсу користувача вимкнена, оскільки налаштування конфігурації програми керуються через змінні середовища. Деякі налаштування можуть бути недоступними для редагування.",
|
||||
"ui_config_disabled_info_title": "Налаштування через UI вимкнено",
|
||||
"ui_config_disabled_info_description": "Налаштування через UI вимкнено, оскільки параметри конфігурації застосунку керуються через змінні середовища. Деякі налаштування можуть бути недоступні для редагування.",
|
||||
"logo_from_url_description": "Вставте пряму URL-адресу зображення (svg, png, webp). Знайдіть іконки на <link href=\"https://selfh.st/icons\">Selfh.st Icons</link> або <link href=\"https://dashboardicons.com\">Dashboard Icons</link>.",
|
||||
"invalid_url": "Недійсна URL-адреса",
|
||||
"require_user_email": "Потрібна адреса електронної пошти",
|
||||
"require_user_email_description": "Вимагає від користувачів наявність адреси електронної пошти. Якщо ця опція вимкнена, користувачі без адреси електронної пошти не зможуть користуватися функціями, для яких потрібна адреса електронної пошти.",
|
||||
"require_user_email_description": "Вимагає наявності електронної адреси у користувачів. Якщо вимкнено, користувачі без електронної адреси не зможуть користуватися функціями, які її вимагають.",
|
||||
"view": "Перегляд",
|
||||
"toggle_columns": "Перемикання стовпців",
|
||||
"locale": "Локаль",
|
||||
"toggle_columns": "Налаштувати стовпці",
|
||||
"locale": "Мова",
|
||||
"ldap_id": "LDAP-ідентифікатор",
|
||||
"reauthentication": "Повторна аутентифікація",
|
||||
"reauthentication": "Повторна автентифікація",
|
||||
"clear_filters": "Очистити фільтри",
|
||||
"default_profile_picture": "Стандартне зображення профілю",
|
||||
"light": "Світла",
|
||||
"dark": "Темна",
|
||||
"system": "Системна",
|
||||
"signup_token_user_groups_description": "Автоматично призначати ці групи користувачам, які реєструються за допомогою цього токена.",
|
||||
"allowed_oidc_clients": "Дозволені клієнти OIDC",
|
||||
"allowed_oidc_clients_description": "Виберіть клієнти OIDC, до яких члени цієї групи користувачів мають право входити.",
|
||||
"allowed_oidc_clients": "Дозволені OIDC-клієнти",
|
||||
"allowed_oidc_clients_description": "Оберіть OIDC-клієнти, до яких дозволено вхід членам цієї групи користувачів.",
|
||||
"unrestrict_oidc_client": "Не обмежувати {clientName}",
|
||||
"confirm_unrestrict_oidc_client_description": "Ви впевнені, що хочете зняти обмеження з клієнта OIDC <b>{clientName}</b>? Це призведе до видалення всіх групових призначень для цього клієнта, і будь-який користувач зможе увійти в систему.",
|
||||
"allowed_oidc_clients_updated_successfully": "Дозволені клієнти OIDC успішно оновлені",
|
||||
"confirm_unrestrict_oidc_client_description": "Ви впевнені, що хочете зняти обмеження з OIDC-клієнта <b>{clientName}</b>? Це видалить усі призначення груп для цього клієнта, і будь-який користувач зможе виконати вхід.",
|
||||
"allowed_oidc_clients_updated_successfully": "Дозволені OIDC-клієнти успішно оновлено",
|
||||
"yes": "Так",
|
||||
"no": "Ні",
|
||||
"restricted": "Обмежений",
|
||||
"scim_provisioning": "Надання SCIM",
|
||||
"scim_provisioning_description": "SCIM-провізінінг дозволяє автоматично надавати та скасовувати доступ користувачам і групам з вашого клієнта OIDC. Дізнайтеся більше в <link href='https://pocket-id.org/docs/configuration/scim'>документації</link>.",
|
||||
"scim_provisioning": "Синхронізація SCIM",
|
||||
"scim_provisioning_description": "Постачання користувачів через SCIM дозволяє автоматично додавати та видаляти користувачів і групи у вашому OIDC-клієнті. Дізнайтеся більше у <link href='https://pocket-id.org/docs/configuration/scim'>документації</link>.",
|
||||
"scim_endpoint": "Кінцева точка SCIM",
|
||||
"scim_token": "Токен SCIM",
|
||||
"last_successful_sync_at": "Остання успішна синхронізація: {time}",
|
||||
"scim_configuration_updated_successfully": "Конфігурація SCIM успішно оновлена.",
|
||||
"scim_enabled_successfully": "SCIM успішно увімкнено.",
|
||||
"scim_disabled_successfully": "SCIM успішно вимкнено.",
|
||||
"disable_scim_provisioning": "Вимкнути надання SCIM",
|
||||
"disable_scim_provisioning_confirm_description": "Ви впевнені, що хочете вимкнути надання доступу SCIM для <b>{clientName}</b>? Це зупинить всі автоматичні процеси надання та скасування доступу для користувачів і груп.",
|
||||
"scim_configuration_updated_successfully": "Конфігурацію SCIM успішно оновлено.",
|
||||
"scim_enabled_successfully": "Синхронізація SCIM успішно увімкнено.",
|
||||
"scim_disabled_successfully": "Синхронізація SCIM успішно вимкнено.",
|
||||
"disable_scim_provisioning": "Вимкнути SCIM синхронізацію",
|
||||
"disable_scim_provisioning_confirm_description": "Ви впевнені, що хочете вимкнути постачання користувачів через SCIM для <b>{clientName}</b>? Це зупинить автоматичне додавання та видалення користувачів і груп.",
|
||||
"scim_sync_failed": "Синхронізація SCIM не вдалася. Перевірте журнали сервера для отримання додаткової інформації.",
|
||||
"scim_sync_successful": "Синхронізація SCIM успішно завершена.",
|
||||
"save_and_sync": "Зберегти та синхронізувати",
|
||||
"scim_save_changes_description": "Перед початком синхронізації SCIM необхідно зберегти зміни. Чи хочете ви зберегти зараз?",
|
||||
"scim_save_changes_description": "Необхідно зберегти зміни перед запуском синхронізації SCIM. Бажаєте зберегти зараз?",
|
||||
"scopes": "Області застосування",
|
||||
"issuer_url": "URL емітента",
|
||||
"smtp_field_required_when_other_provided": "Необхідно, якщо вказано будь-яке налаштування SMTP",
|
||||
"smtp_field_required_when_email_enabled": "Необхідно, якщо увімкнено сповіщення електронною поштою",
|
||||
"smtp_field_required_when_other_provided": "Обов'язково, якщо вказано будь-який параметр SMTP",
|
||||
"smtp_field_required_when_email_enabled": "Обов'язково, якщо увімкнено сповіщення електронною поштою",
|
||||
"renew": "Оновити",
|
||||
"renew_api_key": "Оновити API-ключ",
|
||||
"renew_api_key_description": "Оновлення API-ключа призведе до створення нового ключа. Обов'язково оновіть усі інтеграції, що використовують цей ключ.",
|
||||
"api_key_renewed": "API-ключ оновлено",
|
||||
"app_config_home_page": "Головна сторінка",
|
||||
"app_config_home_page_description": "Сторінка, на яку перенаправляють користувачів після входу в систему.",
|
||||
"app_config_home_page_description": "Сторінка, на яку користувачі перенаправляються після входу.",
|
||||
"email_verification_warning": "Підтвердьте свою адресу електронної пошти",
|
||||
"email_verification_warning_description": "Ваша електронна адреса ще не підтверджена. Будь ласка, підтвердьте її якомога швидше.",
|
||||
"email_verification": "Перевірка електронної адреси",
|
||||
|
||||
@@ -1,63 +1,63 @@
|
||||
{
|
||||
"name": "pocket-id-frontend",
|
||||
"version": "2.2.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"dev": "vite dev --port 3000",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview --port 3000",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"lint": "prettier --check . && eslint .",
|
||||
"format": "prettier --write ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@simplewebauthn/browser": "^13.2.2",
|
||||
"@tailwindcss/vite": "^4.2.0",
|
||||
"axios": "^1.13.5",
|
||||
"clsx": "^2.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"jose": "^6.1.3",
|
||||
"qrcode": "^1.5.4",
|
||||
"runed": "^0.37.1",
|
||||
"sveltekit-superforms": "^2.30.0",
|
||||
"tailwind-merge": "^3.5.0",
|
||||
"zod": "^4.3.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@inlang/paraglide-js": "^2.12.0",
|
||||
"@inlang/plugin-m-function-matcher": "^2.2.1",
|
||||
"@inlang/plugin-message-format": "^4.3.0",
|
||||
"@internationalized/date": "^3.11.0",
|
||||
"@lucide/svelte": "^0.559.0",
|
||||
"@sveltejs/adapter-static": "^3.0.10",
|
||||
"@sveltejs/kit": "^2.53.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
||||
"@types/eslint": "^9.6.1",
|
||||
"@types/node": "^24.10.13",
|
||||
"@types/qrcode": "^1.5.6",
|
||||
"bits-ui": "^2.16.2",
|
||||
"eslint": "^9.39.3",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-svelte": "^3.15.0",
|
||||
"formsnap": "^2.0.1",
|
||||
"globals": "^16.5.0",
|
||||
"mode-watcher": "^1.1.0",
|
||||
"prettier": "^3.8.1",
|
||||
"prettier-plugin-svelte": "^3.5.0",
|
||||
"prettier-plugin-tailwindcss": "^0.7.2",
|
||||
"rollup": "^4.59.0",
|
||||
"svelte": "^5.53.2",
|
||||
"svelte-check": "^4.4.3",
|
||||
"svelte-sonner": "^1.0.7",
|
||||
"tailwind-variants": "^3.2.2",
|
||||
"tailwindcss": "^4.2.0",
|
||||
"tslib": "^2.8.1",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.56.0",
|
||||
"vite": "^7.3.1"
|
||||
}
|
||||
"name": "pocket-id-frontend",
|
||||
"version": "2.3.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"dev": "vite dev --port 3000",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview --port 3000",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"lint": "prettier --check . && eslint .",
|
||||
"format": "prettier --write ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@simplewebauthn/browser": "^13.2.2",
|
||||
"@tailwindcss/vite": "^4.2.0",
|
||||
"axios": "^1.13.5",
|
||||
"clsx": "^2.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"jose": "^6.1.3",
|
||||
"qrcode": "^1.5.4",
|
||||
"runed": "^0.37.1",
|
||||
"sveltekit-superforms": "^2.30.0",
|
||||
"tailwind-merge": "^3.5.0",
|
||||
"zod": "^4.3.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@inlang/paraglide-js": "^2.12.0",
|
||||
"@inlang/plugin-m-function-matcher": "^2.2.1",
|
||||
"@inlang/plugin-message-format": "^4.3.0",
|
||||
"@internationalized/date": "^3.11.0",
|
||||
"@lucide/svelte": "^0.559.0",
|
||||
"@sveltejs/adapter-static": "^3.0.10",
|
||||
"@sveltejs/kit": "^2.53.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
||||
"@types/eslint": "^9.6.1",
|
||||
"@types/node": "^24.10.13",
|
||||
"@types/qrcode": "^1.5.6",
|
||||
"bits-ui": "^2.16.2",
|
||||
"eslint": "^9.39.3",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-svelte": "^3.15.0",
|
||||
"formsnap": "^2.0.1",
|
||||
"globals": "^16.5.0",
|
||||
"mode-watcher": "^1.1.0",
|
||||
"prettier": "^3.8.1",
|
||||
"prettier-plugin-svelte": "^3.5.0",
|
||||
"prettier-plugin-tailwindcss": "^0.7.2",
|
||||
"rollup": "^4.59.0",
|
||||
"svelte": "^5.53.2",
|
||||
"svelte-check": "^4.4.3",
|
||||
"svelte-sonner": "^1.0.7",
|
||||
"tailwind-variants": "^3.2.2",
|
||||
"tailwindcss": "^4.2.0",
|
||||
"tslib": "^2.8.1",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.56.0",
|
||||
"vite": "^7.3.1"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user