@mdguggenbichler/slugbase-core 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/backend/dist/app-factory.d.ts +17 -0
- package/backend/dist/app-factory.d.ts.map +1 -0
- package/backend/dist/app-factory.js +106 -0
- package/backend/dist/app-factory.js.map +1 -0
- package/backend/dist/auth/authorization.d.ts +25 -0
- package/backend/dist/auth/authorization.d.ts.map +1 -0
- package/backend/dist/auth/authorization.js +100 -0
- package/backend/dist/auth/authorization.js.map +1 -0
- package/backend/dist/auth/jwt.d.ts +5 -0
- package/backend/dist/auth/jwt.d.ts.map +1 -0
- package/backend/dist/auth/jwt.js +34 -0
- package/backend/dist/auth/jwt.js.map +1 -0
- package/backend/dist/auth/oidc.d.ts +4 -0
- package/backend/dist/auth/oidc.d.ts.map +1 -0
- package/backend/dist/auth/oidc.js +201 -0
- package/backend/dist/auth/oidc.js.map +1 -0
- package/backend/dist/config/cloud-providers.d.ts +18 -0
- package/backend/dist/config/cloud-providers.d.ts.map +1 -0
- package/backend/dist/config/cloud-providers.js +60 -0
- package/backend/dist/config/cloud-providers.js.map +1 -0
- package/backend/dist/config/cookies.d.ts +17 -0
- package/backend/dist/config/cookies.d.ts.map +1 -0
- package/backend/dist/config/cookies.js +26 -0
- package/backend/dist/config/cookies.js.map +1 -0
- package/backend/dist/config/mode.d.ts +7 -0
- package/backend/dist/config/mode.d.ts.map +1 -0
- package/backend/dist/config/mode.js +7 -0
- package/backend/dist/config/mode.js.map +1 -0
- package/backend/dist/config/swagger.d.ts +2 -0
- package/backend/dist/config/swagger.d.ts.map +1 -0
- package/backend/dist/config/swagger.js +76 -0
- package/backend/dist/config/swagger.js.map +1 -0
- package/backend/dist/config.d.ts +29 -0
- package/backend/dist/config.d.ts.map +1 -0
- package/backend/dist/config.js +41 -0
- package/backend/dist/config.js.map +1 -0
- package/backend/dist/db/index.d.ts +14 -0
- package/backend/dist/db/index.d.ts.map +1 -0
- package/backend/dist/db/index.js +114 -0
- package/backend/dist/db/index.js.map +1 -0
- package/backend/dist/db/migrate-slug-nullable.d.ts +10 -0
- package/backend/dist/db/migrate-slug-nullable.d.ts.map +1 -0
- package/backend/dist/db/migrate-slug-nullable.js +87 -0
- package/backend/dist/db/migrate-slug-nullable.js.map +1 -0
- package/backend/dist/db/migrations/001_migrate_slug_nullable.d.ts +10 -0
- package/backend/dist/db/migrations/001_migrate_slug_nullable.d.ts.map +1 -0
- package/backend/dist/db/migrations/001_migrate_slug_nullable.js +103 -0
- package/backend/dist/db/migrations/001_migrate_slug_nullable.js.map +1 -0
- package/backend/dist/db/migrations/002_add_oidc_custom_endpoints.d.ts +11 -0
- package/backend/dist/db/migrations/002_add_oidc_custom_endpoints.d.ts.map +1 -0
- package/backend/dist/db/migrations/002_add_oidc_custom_endpoints.js +92 -0
- package/backend/dist/db/migrations/002_add_oidc_custom_endpoints.js.map +1 -0
- package/backend/dist/db/migrations/003_add_bookmark_features.d.ts +5 -0
- package/backend/dist/db/migrations/003_add_bookmark_features.d.ts.map +1 -0
- package/backend/dist/db/migrations/003_add_bookmark_features.js +98 -0
- package/backend/dist/db/migrations/003_add_bookmark_features.js.map +1 -0
- package/backend/dist/db/migrations/004_make_slug_globally_unique.d.ts +12 -0
- package/backend/dist/db/migrations/004_make_slug_globally_unique.d.ts.map +1 -0
- package/backend/dist/db/migrations/004_make_slug_globally_unique.js +152 -0
- package/backend/dist/db/migrations/004_make_slug_globally_unique.js.map +1 -0
- package/backend/dist/db/migrations/005_add_email_verification.d.ts +5 -0
- package/backend/dist/db/migrations/005_add_email_verification.d.ts.map +1 -0
- package/backend/dist/db/migrations/005_add_email_verification.js +102 -0
- package/backend/dist/db/migrations/005_add_email_verification.js.map +1 -0
- package/backend/dist/db/migrations/006_refresh_tokens.d.ts +9 -0
- package/backend/dist/db/migrations/006_refresh_tokens.d.ts.map +1 -0
- package/backend/dist/db/migrations/006_refresh_tokens.js +61 -0
- package/backend/dist/db/migrations/006_refresh_tokens.js.map +1 -0
- package/backend/dist/db/migrations/007_password_reset_token_hash.d.ts +10 -0
- package/backend/dist/db/migrations/007_password_reset_token_hash.d.ts.map +1 -0
- package/backend/dist/db/migrations/007_password_reset_token_hash.js +40 -0
- package/backend/dist/db/migrations/007_password_reset_token_hash.js.map +1 -0
- package/backend/dist/db/migrations/008_slug_preferences.d.ts +8 -0
- package/backend/dist/db/migrations/008_slug_preferences.d.ts.map +1 -0
- package/backend/dist/db/migrations/008_slug_preferences.js +24 -0
- package/backend/dist/db/migrations/008_slug_preferences.js.map +1 -0
- package/backend/dist/db/migrations/009_signup_email_verified.d.ts +5 -0
- package/backend/dist/db/migrations/009_signup_email_verified.d.ts.map +1 -0
- package/backend/dist/db/migrations/009_signup_email_verified.js +79 -0
- package/backend/dist/db/migrations/009_signup_email_verified.js.map +1 -0
- package/backend/dist/db/migrations/010_organizations.d.ts +5 -0
- package/backend/dist/db/migrations/010_organizations.d.ts.map +1 -0
- package/backend/dist/db/migrations/010_organizations.js +113 -0
- package/backend/dist/db/migrations/010_organizations.js.map +1 -0
- package/backend/dist/db/migrations/011_org_scoped_teams.d.ts +11 -0
- package/backend/dist/db/migrations/011_org_scoped_teams.d.ts.map +1 -0
- package/backend/dist/db/migrations/011_org_scoped_teams.js +59 -0
- package/backend/dist/db/migrations/011_org_scoped_teams.js.map +1 -0
- package/backend/dist/db/migrations/012_org_invitations_token_hash.d.ts +10 -0
- package/backend/dist/db/migrations/012_org_invitations_token_hash.d.ts.map +1 -0
- package/backend/dist/db/migrations/012_org_invitations_token_hash.js +40 -0
- package/backend/dist/db/migrations/012_org_invitations_token_hash.js.map +1 -0
- package/backend/dist/db/migrations/013_signup_verification_token_hash.d.ts +10 -0
- package/backend/dist/db/migrations/013_signup_verification_token_hash.d.ts.map +1 -0
- package/backend/dist/db/migrations/013_signup_verification_token_hash.js +39 -0
- package/backend/dist/db/migrations/013_signup_verification_token_hash.js.map +1 -0
- package/backend/dist/db/migrations/014_stats_indexes.d.ts +8 -0
- package/backend/dist/db/migrations/014_stats_indexes.d.ts.map +1 -0
- package/backend/dist/db/migrations/014_stats_indexes.js +19 -0
- package/backend/dist/db/migrations/014_stats_indexes.js.map +1 -0
- package/backend/dist/db/migrations/015_api_tokens.d.ts +9 -0
- package/backend/dist/db/migrations/015_api_tokens.d.ts.map +1 -0
- package/backend/dist/db/migrations/015_api_tokens.js +48 -0
- package/backend/dist/db/migrations/015_api_tokens.js.map +1 -0
- package/backend/dist/db/migrations/016_free_plan_grace_ends_at.d.ts +9 -0
- package/backend/dist/db/migrations/016_free_plan_grace_ends_at.d.ts.map +1 -0
- package/backend/dist/db/migrations/016_free_plan_grace_ends_at.js +50 -0
- package/backend/dist/db/migrations/016_free_plan_grace_ends_at.js.map +1 -0
- package/backend/dist/db/migrations/017_ai_suggestions.d.ts +11 -0
- package/backend/dist/db/migrations/017_ai_suggestions.d.ts.map +1 -0
- package/backend/dist/db/migrations/017_ai_suggestions.js +78 -0
- package/backend/dist/db/migrations/017_ai_suggestions.js.map +1 -0
- package/backend/dist/db/migrations/018_ai_cache_output_language.d.ts +10 -0
- package/backend/dist/db/migrations/018_ai_cache_output_language.d.ts.map +1 -0
- package/backend/dist/db/migrations/018_ai_cache_output_language.js +89 -0
- package/backend/dist/db/migrations/018_ai_cache_output_language.js.map +1 -0
- package/backend/dist/db/migrations/019_ai_suggestion_usage.d.ts +10 -0
- package/backend/dist/db/migrations/019_ai_suggestion_usage.d.ts.map +1 -0
- package/backend/dist/db/migrations/019_ai_suggestion_usage.js +47 -0
- package/backend/dist/db/migrations/019_ai_suggestion_usage.js.map +1 -0
- package/backend/dist/db/migrations/020_tenant_scope.d.ts +5 -0
- package/backend/dist/db/migrations/020_tenant_scope.d.ts.map +1 -0
- package/backend/dist/db/migrations/020_tenant_scope.js +105 -0
- package/backend/dist/db/migrations/020_tenant_scope.js.map +1 -0
- package/backend/dist/db/migrations/_legacy_cloud_010_organizations.d.ts +5 -0
- package/backend/dist/db/migrations/_legacy_cloud_010_organizations.d.ts.map +1 -0
- package/backend/dist/db/migrations/_legacy_cloud_010_organizations.js +113 -0
- package/backend/dist/db/migrations/_legacy_cloud_010_organizations.js.map +1 -0
- package/backend/dist/db/migrations/_legacy_cloud_011_org_scoped_teams.d.ts +11 -0
- package/backend/dist/db/migrations/_legacy_cloud_011_org_scoped_teams.d.ts.map +1 -0
- package/backend/dist/db/migrations/_legacy_cloud_011_org_scoped_teams.js +59 -0
- package/backend/dist/db/migrations/_legacy_cloud_011_org_scoped_teams.js.map +1 -0
- package/backend/dist/db/migrations/_legacy_cloud_012_org_invitations_token_hash.d.ts +10 -0
- package/backend/dist/db/migrations/_legacy_cloud_012_org_invitations_token_hash.d.ts.map +1 -0
- package/backend/dist/db/migrations/_legacy_cloud_012_org_invitations_token_hash.js +40 -0
- package/backend/dist/db/migrations/_legacy_cloud_012_org_invitations_token_hash.js.map +1 -0
- package/backend/dist/db/migrations/_legacy_cloud_016_free_plan_grace_ends_at.d.ts +9 -0
- package/backend/dist/db/migrations/_legacy_cloud_016_free_plan_grace_ends_at.d.ts.map +1 -0
- package/backend/dist/db/migrations/_legacy_cloud_016_free_plan_grace_ends_at.js +50 -0
- package/backend/dist/db/migrations/_legacy_cloud_016_free_plan_grace_ends_at.js.map +1 -0
- package/backend/dist/db/migrations/_legacy_cloud_017_ai_suggestions.d.ts +11 -0
- package/backend/dist/db/migrations/_legacy_cloud_017_ai_suggestions.d.ts.map +1 -0
- package/backend/dist/db/migrations/_legacy_cloud_017_ai_suggestions.js +78 -0
- package/backend/dist/db/migrations/_legacy_cloud_017_ai_suggestions.js.map +1 -0
- package/backend/dist/db/migrations/index.d.ts +22 -0
- package/backend/dist/db/migrations/index.d.ts.map +1 -0
- package/backend/dist/db/migrations/index.js +194 -0
- package/backend/dist/db/migrations/index.js.map +1 -0
- package/backend/dist/db/pool.d.ts +13 -0
- package/backend/dist/db/pool.d.ts.map +1 -0
- package/backend/dist/db/pool.js +41 -0
- package/backend/dist/db/pool.js.map +1 -0
- package/backend/dist/db/seed-data.d.ts +66 -0
- package/backend/dist/db/seed-data.d.ts.map +1 -0
- package/backend/dist/db/seed-data.js +394 -0
- package/backend/dist/db/seed-data.js.map +1 -0
- package/backend/dist/db/seed.d.ts +19 -0
- package/backend/dist/db/seed.d.ts.map +1 -0
- package/backend/dist/db/seed.js +406 -0
- package/backend/dist/db/seed.js.map +1 -0
- package/backend/dist/index.d.ts +3 -0
- package/backend/dist/index.d.ts.map +1 -0
- package/backend/dist/index.js +64 -0
- package/backend/dist/index.js.map +1 -0
- package/backend/dist/instrument.d.ts +2 -0
- package/backend/dist/instrument.d.ts.map +1 -0
- package/backend/dist/instrument.js +16 -0
- package/backend/dist/instrument.js.map +1 -0
- package/backend/dist/load-env.d.ts +2 -0
- package/backend/dist/load-env.d.ts.map +1 -0
- package/backend/dist/load-env.js +33 -0
- package/backend/dist/load-env.js.map +1 -0
- package/backend/dist/middleware/auth.d.ts +23 -0
- package/backend/dist/middleware/auth.d.ts.map +1 -0
- package/backend/dist/middleware/auth.js +69 -0
- package/backend/dist/middleware/auth.js.map +1 -0
- package/backend/dist/middleware/error-handler.d.ts +11 -0
- package/backend/dist/middleware/error-handler.d.ts.map +1 -0
- package/backend/dist/middleware/error-handler.js +40 -0
- package/backend/dist/middleware/error-handler.js.map +1 -0
- package/backend/dist/middleware/security.d.ts +26 -0
- package/backend/dist/middleware/security.d.ts.map +1 -0
- package/backend/dist/middleware/security.js +162 -0
- package/backend/dist/middleware/security.js.map +1 -0
- package/backend/dist/middleware/stats-auth.d.ts +7 -0
- package/backend/dist/middleware/stats-auth.d.ts.map +1 -0
- package/backend/dist/middleware/stats-auth.js +20 -0
- package/backend/dist/middleware/stats-auth.js.map +1 -0
- package/backend/dist/middleware/tenant.d.ts +3 -0
- package/backend/dist/middleware/tenant.d.ts.map +1 -0
- package/backend/dist/middleware/tenant.js +13 -0
- package/backend/dist/middleware/tenant.js.map +1 -0
- package/backend/dist/register-routes.d.ts +12 -0
- package/backend/dist/register-routes.d.ts.map +1 -0
- package/backend/dist/register-routes.js +59 -0
- package/backend/dist/register-routes.js.map +1 -0
- package/backend/dist/routes/admin/demo-reset.d.ts +8 -0
- package/backend/dist/routes/admin/demo-reset.d.ts.map +1 -0
- package/backend/dist/routes/admin/demo-reset.js +66 -0
- package/backend/dist/routes/admin/demo-reset.js.map +1 -0
- package/backend/dist/routes/admin/settings.d.ts +3 -0
- package/backend/dist/routes/admin/settings.d.ts.map +1 -0
- package/backend/dist/routes/admin/settings.js +452 -0
- package/backend/dist/routes/admin/settings.js.map +1 -0
- package/backend/dist/routes/admin/stats.d.ts +7 -0
- package/backend/dist/routes/admin/stats.d.ts.map +1 -0
- package/backend/dist/routes/admin/stats.js +66 -0
- package/backend/dist/routes/admin/stats.js.map +1 -0
- package/backend/dist/routes/admin/teams.d.ts +3 -0
- package/backend/dist/routes/admin/teams.d.ts.map +1 -0
- package/backend/dist/routes/admin/teams.js +509 -0
- package/backend/dist/routes/admin/teams.js.map +1 -0
- package/backend/dist/routes/admin/users.d.ts +3 -0
- package/backend/dist/routes/admin/users.d.ts.map +1 -0
- package/backend/dist/routes/admin/users.js +525 -0
- package/backend/dist/routes/admin/users.js.map +1 -0
- package/backend/dist/routes/auth.d.ts +3 -0
- package/backend/dist/routes/auth.d.ts.map +1 -0
- package/backend/dist/routes/auth.js +992 -0
- package/backend/dist/routes/auth.js.map +1 -0
- package/backend/dist/routes/billing.d.ts +8 -0
- package/backend/dist/routes/billing.d.ts.map +1 -0
- package/backend/dist/routes/billing.js +481 -0
- package/backend/dist/routes/billing.js.map +1 -0
- package/backend/dist/routes/bookmarks.d.ts +3 -0
- package/backend/dist/routes/bookmarks.d.ts.map +1 -0
- package/backend/dist/routes/bookmarks.js +1593 -0
- package/backend/dist/routes/bookmarks.js.map +1 -0
- package/backend/dist/routes/config.d.ts +7 -0
- package/backend/dist/routes/config.d.ts.map +1 -0
- package/backend/dist/routes/config.js +52 -0
- package/backend/dist/routes/config.js.map +1 -0
- package/backend/dist/routes/contact.d.ts +9 -0
- package/backend/dist/routes/contact.d.ts.map +1 -0
- package/backend/dist/routes/contact.js +99 -0
- package/backend/dist/routes/contact.js.map +1 -0
- package/backend/dist/routes/csrf.d.ts +3 -0
- package/backend/dist/routes/csrf.d.ts.map +1 -0
- package/backend/dist/routes/csrf.js +39 -0
- package/backend/dist/routes/csrf.js.map +1 -0
- package/backend/dist/routes/dashboard.d.ts +3 -0
- package/backend/dist/routes/dashboard.d.ts.map +1 -0
- package/backend/dist/routes/dashboard.js +212 -0
- package/backend/dist/routes/dashboard.js.map +1 -0
- package/backend/dist/routes/email-verification.d.ts +3 -0
- package/backend/dist/routes/email-verification.d.ts.map +1 -0
- package/backend/dist/routes/email-verification.js +124 -0
- package/backend/dist/routes/email-verification.js.map +1 -0
- package/backend/dist/routes/folders.d.ts +3 -0
- package/backend/dist/routes/folders.d.ts.map +1 -0
- package/backend/dist/routes/folders.js +524 -0
- package/backend/dist/routes/folders.js.map +1 -0
- package/backend/dist/routes/go-helpers.d.ts +18 -0
- package/backend/dist/routes/go-helpers.d.ts.map +1 -0
- package/backend/dist/routes/go-helpers.js +64 -0
- package/backend/dist/routes/go-helpers.js.map +1 -0
- package/backend/dist/routes/go.d.ts +23 -0
- package/backend/dist/routes/go.d.ts.map +1 -0
- package/backend/dist/routes/go.js +361 -0
- package/backend/dist/routes/go.js.map +1 -0
- package/backend/dist/routes/health.d.ts +6 -0
- package/backend/dist/routes/health.d.ts.map +1 -0
- package/backend/dist/routes/health.js +79 -0
- package/backend/dist/routes/health.js.map +1 -0
- package/backend/dist/routes/invitations.d.ts +3 -0
- package/backend/dist/routes/invitations.d.ts.map +1 -0
- package/backend/dist/routes/invitations.js +172 -0
- package/backend/dist/routes/invitations.js.map +1 -0
- package/backend/dist/routes/oidc-providers.d.ts +3 -0
- package/backend/dist/routes/oidc-providers.d.ts.map +1 -0
- package/backend/dist/routes/oidc-providers.js +495 -0
- package/backend/dist/routes/oidc-providers.js.map +1 -0
- package/backend/dist/routes/organizations.d.ts +3 -0
- package/backend/dist/routes/organizations.d.ts.map +1 -0
- package/backend/dist/routes/organizations.js +538 -0
- package/backend/dist/routes/organizations.js.map +1 -0
- package/backend/dist/routes/password-reset.d.ts +3 -0
- package/backend/dist/routes/password-reset.d.ts.map +1 -0
- package/backend/dist/routes/password-reset.js +212 -0
- package/backend/dist/routes/password-reset.js.map +1 -0
- package/backend/dist/routes/redirect.d.ts +3 -0
- package/backend/dist/routes/redirect.d.ts.map +1 -0
- package/backend/dist/routes/redirect.js +124 -0
- package/backend/dist/routes/redirect.js.map +1 -0
- package/backend/dist/routes/tags.d.ts +3 -0
- package/backend/dist/routes/tags.d.ts.map +1 -0
- package/backend/dist/routes/tags.js +302 -0
- package/backend/dist/routes/tags.js.map +1 -0
- package/backend/dist/routes/teams.d.ts +3 -0
- package/backend/dist/routes/teams.d.ts.map +1 -0
- package/backend/dist/routes/teams.js +60 -0
- package/backend/dist/routes/teams.js.map +1 -0
- package/backend/dist/routes/tokens.d.ts +3 -0
- package/backend/dist/routes/tokens.d.ts.map +1 -0
- package/backend/dist/routes/tokens.js +157 -0
- package/backend/dist/routes/tokens.js.map +1 -0
- package/backend/dist/routes/users.d.ts +3 -0
- package/backend/dist/routes/users.d.ts.map +1 -0
- package/backend/dist/routes/users.js +199 -0
- package/backend/dist/routes/users.js.map +1 -0
- package/backend/dist/services/ai-suggestions.d.ts +29 -0
- package/backend/dist/services/ai-suggestions.d.ts.map +1 -0
- package/backend/dist/services/ai-suggestions.js +163 -0
- package/backend/dist/services/ai-suggestions.js.map +1 -0
- package/backend/dist/services/api-tokens.d.ts +66 -0
- package/backend/dist/services/api-tokens.d.ts.map +1 -0
- package/backend/dist/services/api-tokens.js +129 -0
- package/backend/dist/services/api-tokens.js.map +1 -0
- package/backend/dist/services/fetch-page-metadata.d.ts +15 -0
- package/backend/dist/services/fetch-page-metadata.d.ts.map +1 -0
- package/backend/dist/services/fetch-page-metadata.js +205 -0
- package/backend/dist/services/fetch-page-metadata.js.map +1 -0
- package/backend/dist/services/stats.d.ts +73 -0
- package/backend/dist/services/stats.d.ts.map +1 -0
- package/backend/dist/services/stats.js +145 -0
- package/backend/dist/services/stats.js.map +1 -0
- package/backend/dist/types/oidc-provider.d.ts +17 -0
- package/backend/dist/types/oidc-provider.d.ts.map +1 -0
- package/backend/dist/types/oidc-provider.js +2 -0
- package/backend/dist/types/oidc-provider.js.map +1 -0
- package/backend/dist/types.d.ts +86 -0
- package/backend/dist/types.d.ts.map +1 -0
- package/backend/dist/types.js +2 -0
- package/backend/dist/types.js.map +1 -0
- package/backend/dist/utils/ai-feature.d.ts +23 -0
- package/backend/dist/utils/ai-feature.d.ts.map +1 -0
- package/backend/dist/utils/ai-feature.js +62 -0
- package/backend/dist/utils/ai-feature.js.map +1 -0
- package/backend/dist/utils/email.d.ts +40 -0
- package/backend/dist/utils/email.d.ts.map +1 -0
- package/backend/dist/utils/email.js +456 -0
- package/backend/dist/utils/email.js.map +1 -0
- package/backend/dist/utils/encryption.d.ts +18 -0
- package/backend/dist/utils/encryption.d.ts.map +1 -0
- package/backend/dist/utils/encryption.js +95 -0
- package/backend/dist/utils/encryption.js.map +1 -0
- package/backend/dist/utils/env-validation.d.ts +6 -0
- package/backend/dist/utils/env-validation.d.ts.map +1 -0
- package/backend/dist/utils/env-validation.js +51 -0
- package/backend/dist/utils/env-validation.js.map +1 -0
- package/backend/dist/utils/jwt.d.ts +20 -0
- package/backend/dist/utils/jwt.d.ts.map +1 -0
- package/backend/dist/utils/jwt.js +48 -0
- package/backend/dist/utils/jwt.js.map +1 -0
- package/backend/dist/utils/org-cleanup.d.ts +6 -0
- package/backend/dist/utils/org-cleanup.d.ts.map +1 -0
- package/backend/dist/utils/org-cleanup.js +37 -0
- package/backend/dist/utils/org-cleanup.js.map +1 -0
- package/backend/dist/utils/organizations.d.ts +12 -0
- package/backend/dist/utils/organizations.d.ts.map +1 -0
- package/backend/dist/utils/organizations.js +24 -0
- package/backend/dist/utils/organizations.js.map +1 -0
- package/backend/dist/utils/plan-errors.d.ts +18 -0
- package/backend/dist/utils/plan-errors.d.ts.map +1 -0
- package/backend/dist/utils/plan-errors.js +21 -0
- package/backend/dist/utils/plan-errors.js.map +1 -0
- package/backend/dist/utils/refresh-token.d.ts +31 -0
- package/backend/dist/utils/refresh-token.d.ts.map +1 -0
- package/backend/dist/utils/refresh-token.js +63 -0
- package/backend/dist/utils/refresh-token.js.map +1 -0
- package/backend/dist/utils/session-store.d.ts +46 -0
- package/backend/dist/utils/session-store.d.ts.map +1 -0
- package/backend/dist/utils/session-store.js +222 -0
- package/backend/dist/utils/session-store.js.map +1 -0
- package/backend/dist/utils/tenant.d.ts +5 -0
- package/backend/dist/utils/tenant.d.ts.map +1 -0
- package/backend/dist/utils/tenant.js +12 -0
- package/backend/dist/utils/tenant.js.map +1 -0
- package/backend/dist/utils/user-key.d.ts +24 -0
- package/backend/dist/utils/user-key.d.ts.map +1 -0
- package/backend/dist/utils/user-key.js +116 -0
- package/backend/dist/utils/user-key.js.map +1 -0
- package/backend/dist/utils/validation.d.ts +91 -0
- package/backend/dist/utils/validation.d.ts.map +1 -0
- package/backend/dist/utils/validation.js +337 -0
- package/backend/dist/utils/validation.js.map +1 -0
- package/backend/index.js +15 -0
- package/frontend/index.js +5 -0
- package/frontend/index.tsx +7 -0
- package/package.json +16 -0
- package/types/index.js +4 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import passport from 'passport';
|
|
2
|
+
import { validateToken } from '../services/api-tokens.js';
|
|
3
|
+
// Type guard to check if request is AuthRequest
|
|
4
|
+
export function isAuthRequest(req) {
|
|
5
|
+
return 'user' in req;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Middleware to authenticate requests using JWT or API token.
|
|
9
|
+
* Priority: JWT (cookie or Bearer) → API token (Bearer with sb_ prefix).
|
|
10
|
+
* If JWT fails and Bearer token starts with sb_, tries API token lookup.
|
|
11
|
+
*/
|
|
12
|
+
export function requireAuth() {
|
|
13
|
+
return (req, res, next) => {
|
|
14
|
+
passport.authenticate('jwt', { session: false }, async (err, user) => {
|
|
15
|
+
if (err) {
|
|
16
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
17
|
+
}
|
|
18
|
+
if (user) {
|
|
19
|
+
req.user = user;
|
|
20
|
+
return next();
|
|
21
|
+
}
|
|
22
|
+
// JWT failed; try API token if Bearer header present
|
|
23
|
+
const authHeader = req.headers.authorization;
|
|
24
|
+
if (authHeader?.startsWith('Bearer ')) {
|
|
25
|
+
const token = authHeader.substring(7);
|
|
26
|
+
if (token.startsWith('sb_')) {
|
|
27
|
+
const apiUser = await validateToken(token);
|
|
28
|
+
if (apiUser) {
|
|
29
|
+
req.user = apiUser;
|
|
30
|
+
return next();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
35
|
+
})(req, res, next);
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Middleware to authenticate and require global admin.
|
|
40
|
+
* Supports JWT and API token same as requireAuth.
|
|
41
|
+
*/
|
|
42
|
+
export function requireAdmin() {
|
|
43
|
+
return (req, res, next) => {
|
|
44
|
+
passport.authenticate('jwt', { session: false }, async (err, user) => {
|
|
45
|
+
if (err) {
|
|
46
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
47
|
+
}
|
|
48
|
+
if (!user) {
|
|
49
|
+
const authHeader = req.headers.authorization;
|
|
50
|
+
if (authHeader?.startsWith('Bearer ')) {
|
|
51
|
+
const token = authHeader.substring(7);
|
|
52
|
+
if (token.startsWith('sb_')) {
|
|
53
|
+
user = await validateToken(token);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (!user) {
|
|
58
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
59
|
+
}
|
|
60
|
+
const isGlobalAdmin = user.is_admin === true || user.is_admin === 1;
|
|
61
|
+
if (!isGlobalAdmin) {
|
|
62
|
+
return res.status(403).json({ error: 'Forbidden' });
|
|
63
|
+
}
|
|
64
|
+
req.user = user;
|
|
65
|
+
next();
|
|
66
|
+
})(req, res, next);
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from 'express';
|
|
2
|
+
/**
|
|
3
|
+
* Error handling middleware
|
|
4
|
+
* Prevents information disclosure in production
|
|
5
|
+
*/
|
|
6
|
+
export declare function errorHandler(err: any, req: Request, res: Response, next: NextFunction): Response<any, Record<string, any>>;
|
|
7
|
+
/**
|
|
8
|
+
* 404 handler
|
|
9
|
+
*/
|
|
10
|
+
export declare function notFoundHandler(req: Request, res: Response): void;
|
|
11
|
+
//# sourceMappingURL=error-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG1D;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,sCA8BrF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,QAE1D"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as Sentry from '@sentry/node';
|
|
2
|
+
/**
|
|
3
|
+
* Error handling middleware
|
|
4
|
+
* Prevents information disclosure in production
|
|
5
|
+
*/
|
|
6
|
+
export function errorHandler(err, req, res, next) {
|
|
7
|
+
// Report to Sentry when configured (no-op when SENTRY_DSN is unset)
|
|
8
|
+
Sentry.captureException(err);
|
|
9
|
+
// Log error details server-side
|
|
10
|
+
console.error('Error:', {
|
|
11
|
+
message: err.message,
|
|
12
|
+
stack: process.env.NODE_ENV === 'development' ? err.stack : undefined,
|
|
13
|
+
path: req.path,
|
|
14
|
+
method: req.method,
|
|
15
|
+
});
|
|
16
|
+
// Don't expose error details in production (M5: never send err.message or stack)
|
|
17
|
+
if (process.env.NODE_ENV === 'production') {
|
|
18
|
+
const status = err.statusCode || 500;
|
|
19
|
+
const safeMessages = {
|
|
20
|
+
400: 'Bad request',
|
|
21
|
+
401: 'Unauthorized',
|
|
22
|
+
403: 'Forbidden',
|
|
23
|
+
404: 'Not found',
|
|
24
|
+
};
|
|
25
|
+
const safeMessage = status in safeMessages ? safeMessages[status] : 'Internal server error';
|
|
26
|
+
return res.status(status).json({ error: safeMessage });
|
|
27
|
+
}
|
|
28
|
+
// Development: show more details
|
|
29
|
+
return res.status(err.statusCode || 500).json({
|
|
30
|
+
error: err.message || 'An error occurred',
|
|
31
|
+
...(process.env.NODE_ENV === 'development' && { stack: err.stack }),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 404 handler
|
|
36
|
+
*/
|
|
37
|
+
export function notFoundHandler(req, res) {
|
|
38
|
+
res.status(404).json({ error: 'Not found' });
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=error-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;AAEvC;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,GAAQ,EAAE,GAAY,EAAE,GAAa,EAAE,IAAkB;IACpF,oEAAoE;IACpE,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAE7B,gCAAgC;IAChC,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE;QACtB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;QACrE,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,MAAM,EAAE,GAAG,CAAC,MAAM;KACnB,CAAC,CAAC;IAEH,iFAAiF;IACjF,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC;QACrC,MAAM,YAAY,GAA2B;YAC3C,GAAG,EAAE,aAAa;YAClB,GAAG,EAAE,cAAc;YACnB,GAAG,EAAE,WAAW;YAChB,GAAG,EAAE,WAAW;SACjB,CAAC;QACF,MAAM,WAAW,GAAG,MAAM,IAAI,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC;QAC5F,OAAO,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,iCAAiC;IACjC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;QAC5C,KAAK,EAAE,GAAG,CAAC,OAAO,IAAI,mBAAmB;QACzC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC;KACpE,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,GAAY,EAAE,GAAa;IACzD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare const authRateLimiter: ((req: any, res: any, next: any) => any) | import("express-rate-limit").RateLimitRequestHandler;
|
|
2
|
+
/** Refresh token: more lenient - 401 is expected when unauthenticated (e.g. signup/login page) */
|
|
3
|
+
export declare const refreshRateLimiter: ((req: any, res: any, next: any) => any) | import("express-rate-limit").RateLimitRequestHandler;
|
|
4
|
+
export declare const generalRateLimiter: ((req: any, res: any, next: any) => any) | import("express-rate-limit").RateLimitRequestHandler;
|
|
5
|
+
export declare const strictRateLimiter: ((req: any, res: any, next: any) => any) | import("express-rate-limit").RateLimitRequestHandler;
|
|
6
|
+
/** Contact form: strict limit to prevent abuse and PII flooding (M1) */
|
|
7
|
+
export declare const contactRateLimiter: ((req: any, res: any, next: any) => any) | import("express-rate-limit").RateLimitRequestHandler;
|
|
8
|
+
/** Redirect endpoint: stricter than general to reduce abuse/crawler load (M4) */
|
|
9
|
+
export declare const redirectRateLimiter: ((req: any, res: any, next: any) => any) | import("express-rate-limit").RateLimitRequestHandler;
|
|
10
|
+
/** API token creation: limit to prevent abuse */
|
|
11
|
+
export declare const tokenCreateRateLimiter: ((req: any, res: any, next: any) => any) | import("express-rate-limit").RateLimitRequestHandler;
|
|
12
|
+
/**
|
|
13
|
+
* Security headers middleware
|
|
14
|
+
*/
|
|
15
|
+
export declare function setupSecurityHeaders(): (req: import("http").IncomingMessage, res: import("http").ServerResponse, next: (err?: unknown) => void) => void;
|
|
16
|
+
/**
|
|
17
|
+
* CSRF protection middleware (custom implementation for JWT-based auth)
|
|
18
|
+
* Generates and validates CSRF tokens stored in httpOnly cookies
|
|
19
|
+
* Note: SameSite=strict cookies provide good CSRF protection, but tokens add defense in depth
|
|
20
|
+
*/
|
|
21
|
+
export declare function csrfProtection(req: any, res: any, next: any): any;
|
|
22
|
+
/**
|
|
23
|
+
* Generate CSRF token and set cookie
|
|
24
|
+
*/
|
|
25
|
+
export declare function generateCSRFToken(req: any, res: any): string;
|
|
26
|
+
//# sourceMappingURL=security.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../src/middleware/security.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,eAAe,SAFE,GAAG,OAAO,GAAG,QAAQ,GAAG,gEAWhD,CAAC;AAEP,kGAAkG;AAClG,eAAO,MAAM,kBAAkB,SAdD,GAAG,OAAO,GAAG,QAAQ,GAAG,gEAuBhD,CAAC;AAEP,eAAO,MAAM,kBAAkB,SAzBD,GAAG,OAAO,GAAG,QAAQ,GAAG,gEAgChD,CAAC;AAEP,eAAO,MAAM,iBAAiB,SAlCA,GAAG,OAAO,GAAG,QAAQ,GAAG,gEA0ChD,CAAC;AAEP,wEAAwE;AACxE,eAAO,MAAM,kBAAkB,SA7CD,GAAG,OAAO,GAAG,QAAQ,GAAG,gEAqDhD,CAAC;AAEP,iFAAiF;AACjF,eAAO,MAAM,mBAAmB,SAxDF,GAAG,OAAO,GAAG,QAAQ,GAAG,gEAgEhD,CAAC;AAEP,iDAAiD;AACjD,eAAO,MAAM,sBAAsB,SAnEL,GAAG,OAAO,GAAG,QAAQ,GAAG,gEA2EhD,CAAC;AAEP;;GAEG;AACH,wBAAgB,oBAAoB,wFA8ElC,CAAD,4BApCA;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,OAmB3D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,MAAM,CAe5D"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import rateLimit from 'express-rate-limit';
|
|
2
|
+
import helmet from 'helmet';
|
|
3
|
+
import crypto from 'crypto';
|
|
4
|
+
/**
|
|
5
|
+
* Rate limiting configuration
|
|
6
|
+
* Disabled in development for easier testing
|
|
7
|
+
*/
|
|
8
|
+
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
9
|
+
// No-op rate limiter for development (allows all requests)
|
|
10
|
+
const noOpRateLimiter = (req, res, next) => next();
|
|
11
|
+
export const authRateLimiter = isDevelopment
|
|
12
|
+
? noOpRateLimiter
|
|
13
|
+
: rateLimit({
|
|
14
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
15
|
+
max: 300, // Limit each IP to 300 failed auth attempts per windowMs
|
|
16
|
+
message: 'Too many authentication attempts, please try again later.',
|
|
17
|
+
standardHeaders: true,
|
|
18
|
+
legacyHeaders: false,
|
|
19
|
+
skipSuccessfulRequests: true, // Don't count successful requests
|
|
20
|
+
});
|
|
21
|
+
/** Refresh token: more lenient - 401 is expected when unauthenticated (e.g. signup/login page) */
|
|
22
|
+
export const refreshRateLimiter = isDevelopment
|
|
23
|
+
? noOpRateLimiter
|
|
24
|
+
: rateLimit({
|
|
25
|
+
windowMs: 15 * 60 * 1000,
|
|
26
|
+
max: 500, // Higher limit; failures are often from unauthenticated users checking /auth/me
|
|
27
|
+
message: 'Too many requests, please try again later.',
|
|
28
|
+
standardHeaders: true,
|
|
29
|
+
legacyHeaders: false,
|
|
30
|
+
skipSuccessfulRequests: true,
|
|
31
|
+
});
|
|
32
|
+
export const generalRateLimiter = isDevelopment
|
|
33
|
+
? noOpRateLimiter
|
|
34
|
+
: rateLimit({
|
|
35
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
36
|
+
max: 2000, // Limit each IP to 2000 requests per windowMs
|
|
37
|
+
standardHeaders: true,
|
|
38
|
+
legacyHeaders: false,
|
|
39
|
+
});
|
|
40
|
+
export const strictRateLimiter = isDevelopment
|
|
41
|
+
? noOpRateLimiter
|
|
42
|
+
: rateLimit({
|
|
43
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
44
|
+
max: 500, // Limit each IP to 500 requests per windowMs
|
|
45
|
+
message: 'Too many requests, please try again later.',
|
|
46
|
+
standardHeaders: true,
|
|
47
|
+
legacyHeaders: false,
|
|
48
|
+
});
|
|
49
|
+
/** Contact form: strict limit to prevent abuse and PII flooding (M1) */
|
|
50
|
+
export const contactRateLimiter = isDevelopment
|
|
51
|
+
? noOpRateLimiter
|
|
52
|
+
: rateLimit({
|
|
53
|
+
windowMs: 60 * 60 * 1000, // 1 hour
|
|
54
|
+
max: 10,
|
|
55
|
+
message: 'Too many contact form submissions. Please try again later.',
|
|
56
|
+
standardHeaders: true,
|
|
57
|
+
legacyHeaders: false,
|
|
58
|
+
});
|
|
59
|
+
/** Redirect endpoint: stricter than general to reduce abuse/crawler load (M4) */
|
|
60
|
+
export const redirectRateLimiter = isDevelopment
|
|
61
|
+
? noOpRateLimiter
|
|
62
|
+
: rateLimit({
|
|
63
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
64
|
+
max: 200,
|
|
65
|
+
message: 'Too many redirect requests. Please try again later.',
|
|
66
|
+
standardHeaders: true,
|
|
67
|
+
legacyHeaders: false,
|
|
68
|
+
});
|
|
69
|
+
/** API token creation: limit to prevent abuse */
|
|
70
|
+
export const tokenCreateRateLimiter = isDevelopment
|
|
71
|
+
? noOpRateLimiter
|
|
72
|
+
: rateLimit({
|
|
73
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
74
|
+
max: 10,
|
|
75
|
+
message: 'Too many token creation attempts. Please try again later.',
|
|
76
|
+
standardHeaders: true,
|
|
77
|
+
legacyHeaders: false,
|
|
78
|
+
});
|
|
79
|
+
/**
|
|
80
|
+
* Security headers middleware
|
|
81
|
+
*/
|
|
82
|
+
export function setupSecurityHeaders() {
|
|
83
|
+
// Only enable HSTS if we're actually using HTTPS
|
|
84
|
+
const baseUrl = process.env.BASE_URL || 'http://localhost:5000';
|
|
85
|
+
const isHttps = baseUrl.startsWith('https://');
|
|
86
|
+
const cspDirectives = {
|
|
87
|
+
defaultSrc: ["'self'"],
|
|
88
|
+
styleSrc: ["'self'", "'unsafe-inline'"], // Swagger UI needs inline styles
|
|
89
|
+
scriptSrc: ["'self'"],
|
|
90
|
+
imgSrc: ["'self'", "data:", "https:"], // Allow data URIs and HTTPS images (for favicons)
|
|
91
|
+
connectSrc: [
|
|
92
|
+
"'self'",
|
|
93
|
+
// Sentry error tracking (ingest endpoints vary by region)
|
|
94
|
+
"https://*.ingest.sentry.io",
|
|
95
|
+
"https://*.ingest.de.sentry.io",
|
|
96
|
+
"https://*.ingest.eu.sentry.io",
|
|
97
|
+
],
|
|
98
|
+
fontSrc: ["'self'"],
|
|
99
|
+
objectSrc: ["'none'"],
|
|
100
|
+
mediaSrc: ["'self'"],
|
|
101
|
+
frameSrc: ["'self'"], // Allow iframes for Swagger UI
|
|
102
|
+
};
|
|
103
|
+
// Only upgrade insecure requests when using HTTPS (set to null to disable when using HTTP)
|
|
104
|
+
if (isHttps) {
|
|
105
|
+
cspDirectives.upgradeInsecureRequests = [];
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
cspDirectives.upgradeInsecureRequests = null; // Explicitly disable when using HTTP
|
|
109
|
+
}
|
|
110
|
+
return helmet({
|
|
111
|
+
contentSecurityPolicy: {
|
|
112
|
+
directives: cspDirectives,
|
|
113
|
+
},
|
|
114
|
+
crossOriginEmbedderPolicy: false, // Disable for compatibility
|
|
115
|
+
crossOriginOpenerPolicy: false, // Disable for compatibility (can cause issues with HTTP)
|
|
116
|
+
hsts: isHttps ? {
|
|
117
|
+
maxAge: 31536000, // 1 year
|
|
118
|
+
includeSubDomains: true,
|
|
119
|
+
preload: true,
|
|
120
|
+
} : false, // Disable HSTS when not using HTTPS
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* CSRF protection middleware (custom implementation for JWT-based auth)
|
|
125
|
+
* Generates and validates CSRF tokens stored in httpOnly cookies
|
|
126
|
+
* Note: SameSite=strict cookies provide good CSRF protection, but tokens add defense in depth
|
|
127
|
+
*/
|
|
128
|
+
export function csrfProtection(req, res, next) {
|
|
129
|
+
// Get token from header or body
|
|
130
|
+
const token = req.headers['x-csrf-token'] || req.body?.csrfToken;
|
|
131
|
+
const cookieToken = req.cookies?._csrf;
|
|
132
|
+
// If no cookie token exists, generate one (for first request)
|
|
133
|
+
if (!cookieToken) {
|
|
134
|
+
generateCSRFToken(req, res);
|
|
135
|
+
// Allow first request to proceed (they'll get token in response)
|
|
136
|
+
return next();
|
|
137
|
+
}
|
|
138
|
+
// Validate token for state-changing operations
|
|
139
|
+
if (token && token === cookieToken) {
|
|
140
|
+
return next();
|
|
141
|
+
}
|
|
142
|
+
// If token doesn't match, return error
|
|
143
|
+
return res.status(403).json({ error: 'Invalid CSRF token' });
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Generate CSRF token and set cookie
|
|
147
|
+
*/
|
|
148
|
+
export function generateCSRFToken(req, res) {
|
|
149
|
+
const token = crypto.randomBytes(32).toString('hex');
|
|
150
|
+
// Only use secure cookies when actually using HTTPS (check BASE_URL)
|
|
151
|
+
const baseUrl = process.env.BASE_URL || 'http://localhost:5000';
|
|
152
|
+
const isHttps = baseUrl.startsWith('https://');
|
|
153
|
+
const isProduction = process.env.NODE_ENV === 'production' && isHttps;
|
|
154
|
+
res.cookie('_csrf', token, {
|
|
155
|
+
httpOnly: true,
|
|
156
|
+
secure: isProduction, // Only secure when using HTTPS
|
|
157
|
+
sameSite: 'strict',
|
|
158
|
+
maxAge: 24 * 60 * 60 * 1000, // 24 hours
|
|
159
|
+
});
|
|
160
|
+
return token;
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=security.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.js","sourceRoot":"","sources":["../../src/middleware/security.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret-based auth for stats endpoint.
|
|
3
|
+
* Uses X-Stats-Secret header; constant-time comparison; returns 404 on invalid (no info leak).
|
|
4
|
+
*/
|
|
5
|
+
import { Request, Response, NextFunction } from 'express';
|
|
6
|
+
export declare function statsSecretAuth(req: Request, res: Response, next: NextFunction): void;
|
|
7
|
+
//# sourceMappingURL=stats-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats-auth.d.ts","sourceRoot":"","sources":["../../src/middleware/stats-auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG1D,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAgBrF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret-based auth for stats endpoint.
|
|
3
|
+
* Uses X-Stats-Secret header; constant-time comparison; returns 404 on invalid (no info leak).
|
|
4
|
+
*/
|
|
5
|
+
import crypto from 'crypto';
|
|
6
|
+
export function statsSecretAuth(req, res, next) {
|
|
7
|
+
const secret = process.env.STATS_ENDPOINT_SECRET?.trim();
|
|
8
|
+
if (!secret) {
|
|
9
|
+
res.status(404).end();
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const headerSecret = req.headers['x-stats-secret'];
|
|
13
|
+
const provided = typeof headerSecret === 'string' ? headerSecret : '';
|
|
14
|
+
if (provided.length !== secret.length || !crypto.timingSafeEqual(Buffer.from(provided, 'utf8'), Buffer.from(secret, 'utf8'))) {
|
|
15
|
+
res.status(404).end();
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
next();
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=stats-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats-auth.js","sourceRoot":"","sources":["../../src/middleware/stats-auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,UAAU,eAAe,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;IAC7E,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,IAAI,EAAE,CAAC;IACzD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QACtB,OAAO;IACT,CAAC;IAED,MAAM,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,OAAO,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IAEtE,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;QAC7H,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QACtB,OAAO;IACT,CAAC;IAED,IAAI,EAAE,CAAC;AACT,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenant.d.ts","sourceRoot":"","sources":["../../src/middleware/tenant.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG/D,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAYvF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DEFAULT_TENANT_ID } from '../utils/tenant.js';
|
|
2
|
+
export function tenantMiddleware(req, _res, next) {
|
|
3
|
+
let tenantId = DEFAULT_TENANT_ID;
|
|
4
|
+
if (process.env.NODE_ENV === 'test') {
|
|
5
|
+
const testTenant = req.header('x-test-tenant')?.trim();
|
|
6
|
+
if (testTenant) {
|
|
7
|
+
tenantId = testTenant;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
req.tenantId = tenantId;
|
|
11
|
+
next();
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=tenant.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenant.js","sourceRoot":"","sources":["../../src/middleware/tenant.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,UAAU,gBAAgB,CAAC,GAAY,EAAE,IAAc,EAAE,IAAkB;IAC/E,IAAI,QAAQ,GAAG,iBAAiB,CAAC;IAEjC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QACpC,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,IAAI,EAAE,CAAC;QACvD,IAAI,UAAU,EAAE,CAAC;YACf,QAAQ,GAAG,UAAU,CAAC;QACxB,CAAC;IACH,CAAC;IAEA,GAAuC,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7D,IAAI,EAAE,CAAC;AACT,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mounts all core API routes and /go slug routes on the Express app.
|
|
3
|
+
* Does NOT add static file serving or error handlers.
|
|
4
|
+
*/
|
|
5
|
+
import express from 'express';
|
|
6
|
+
export interface CoreRouteDeps {
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Register all core API and /go routes. Call after createApp().
|
|
10
|
+
*/
|
|
11
|
+
export declare function registerCoreRoutes(app: express.Express, _deps?: CoreRouteDeps): void;
|
|
12
|
+
//# sourceMappingURL=register-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-routes.d.ts","sourceRoot":"","sources":["../src/register-routes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,OAAO,MAAM,SAAS,CAAC;AAqB9B,MAAM,WAAW,aAAa;CAE7B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,aAAa,GAAG,IAAI,CAiCpF"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mounts all core API routes and /go slug routes on the Express app.
|
|
3
|
+
* Does NOT add static file serving or error handlers.
|
|
4
|
+
*/
|
|
5
|
+
import authRoutes from './routes/auth.js';
|
|
6
|
+
import bookmarkRoutes from './routes/bookmarks.js';
|
|
7
|
+
import folderRoutes from './routes/folders.js';
|
|
8
|
+
import tagRoutes from './routes/tags.js';
|
|
9
|
+
import goRoutes, { optionalAuthForGo, handleGoSlug, handleGoRemember } from './routes/go.js';
|
|
10
|
+
import userRoutes from './routes/users.js';
|
|
11
|
+
import teamRoutes from './routes/teams.js';
|
|
12
|
+
import oidcProviderRoutes from './routes/oidc-providers.js';
|
|
13
|
+
import adminUserRoutes from './routes/admin/users.js';
|
|
14
|
+
import adminTeamRoutes from './routes/admin/teams.js';
|
|
15
|
+
import adminSettingsRoutes from './routes/admin/settings.js';
|
|
16
|
+
import adminStatsRoutes from './routes/admin/stats.js';
|
|
17
|
+
import passwordResetRoutes from './routes/password-reset.js';
|
|
18
|
+
import emailVerificationRoutes from './routes/email-verification.js';
|
|
19
|
+
import dashboardRoutes from './routes/dashboard.js';
|
|
20
|
+
import healthRoutes from './routes/health.js';
|
|
21
|
+
import tokenRoutes from './routes/tokens.js';
|
|
22
|
+
import configRoutes from './routes/config.js';
|
|
23
|
+
import { redirectRateLimiter } from './middleware/security.js';
|
|
24
|
+
/**
|
|
25
|
+
* Register all core API and /go routes. Call after createApp().
|
|
26
|
+
*/
|
|
27
|
+
export function registerCoreRoutes(app, _deps) {
|
|
28
|
+
app.use('/api/auth', authRoutes);
|
|
29
|
+
app.use('/api/password-reset', passwordResetRoutes);
|
|
30
|
+
app.use('/api/email-verification', emailVerificationRoutes);
|
|
31
|
+
app.use('/api/bookmarks', bookmarkRoutes);
|
|
32
|
+
app.use('/api/folders', folderRoutes);
|
|
33
|
+
app.use('/api/tags', tagRoutes);
|
|
34
|
+
app.use('/api/users', userRoutes);
|
|
35
|
+
app.use('/api/teams', teamRoutes);
|
|
36
|
+
app.use('/api/tokens', tokenRoutes);
|
|
37
|
+
app.use('/api/config', configRoutes);
|
|
38
|
+
app.use('/api/oidc-providers', oidcProviderRoutes);
|
|
39
|
+
app.use('/api/admin/users', adminUserRoutes);
|
|
40
|
+
app.use('/api/admin/teams', adminTeamRoutes);
|
|
41
|
+
app.use('/api/admin/settings', adminSettingsRoutes);
|
|
42
|
+
app.use('/api/admin/stats', adminStatsRoutes);
|
|
43
|
+
app.use('/api/dashboard', dashboardRoutes);
|
|
44
|
+
app.use('/api', healthRoutes);
|
|
45
|
+
app.use('/api/go', goRoutes);
|
|
46
|
+
if (process.env.SENTRY_DEBUG === 'true') {
|
|
47
|
+
app.get('/api/debug-sentry', () => {
|
|
48
|
+
throw new Error('Sentry backend test error');
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
app.get('/go/:slug/remember/:bookmarkId', redirectRateLimiter, optionalAuthForGo, (req, res) => {
|
|
52
|
+
handleGoRemember(req, res).catch((err) => {
|
|
53
|
+
console.error('Go remember error:', err);
|
|
54
|
+
res.status(500).send('Internal Server Error');
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
app.get('/go/:slug', redirectRateLimiter, optionalAuthForGo, handleGoSlug);
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=register-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-routes.js","sourceRoot":"","sources":["../src/register-routes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,UAAU,MAAM,kBAAkB,CAAC;AAC1C,OAAO,cAAc,MAAM,uBAAuB,CAAC;AACnD,OAAO,YAAY,MAAM,qBAAqB,CAAC;AAC/C,OAAO,SAAS,MAAM,kBAAkB,CAAC;AACzC,OAAO,QAAQ,EAAE,EAAE,iBAAiB,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC7F,OAAO,UAAU,MAAM,mBAAmB,CAAC;AAC3C,OAAO,UAAU,MAAM,mBAAmB,CAAC;AAC3C,OAAO,kBAAkB,MAAM,4BAA4B,CAAC;AAC5D,OAAO,eAAe,MAAM,yBAAyB,CAAC;AACtD,OAAO,eAAe,MAAM,yBAAyB,CAAC;AACtD,OAAO,mBAAmB,MAAM,4BAA4B,CAAC;AAC7D,OAAO,gBAAgB,MAAM,yBAAyB,CAAC;AACvD,OAAO,mBAAmB,MAAM,4BAA4B,CAAC;AAC7D,OAAO,uBAAuB,MAAM,gCAAgC,CAAC;AACrE,OAAO,eAAe,MAAM,uBAAuB,CAAC;AACpD,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAC9C,OAAO,WAAW,MAAM,oBAAoB,CAAC;AAC7C,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAM/D;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAoB,EAAE,KAAqB;IAC5E,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IACjC,GAAG,CAAC,GAAG,CAAC,qBAAqB,EAAE,mBAAmB,CAAC,CAAC;IACpD,GAAG,CAAC,GAAG,CAAC,yBAAyB,EAAE,uBAAuB,CAAC,CAAC;IAC5D,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC;IAC1C,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;IACtC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAChC,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IAClC,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IAClC,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IACpC,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;IACrC,GAAG,CAAC,GAAG,CAAC,qBAAqB,EAAE,kBAAkB,CAAC,CAAC;IACnD,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,eAAe,CAAC,CAAC;IAC7C,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,eAAe,CAAC,CAAC;IAC7C,GAAG,CAAC,GAAG,CAAC,qBAAqB,EAAE,mBAAmB,CAAC,CAAC;IACpD,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,gBAAgB,CAAC,CAAC;IAC9C,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAE,eAAe,CAAC,CAAC;IAC3C,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC9B,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAE7B,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,MAAM,EAAE,CAAC;QACxC,GAAG,CAAC,GAAG,CAAC,mBAAmB,EAAE,GAAG,EAAE;YAChC,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC;IAED,GAAG,CAAC,GAAG,CAAC,gCAAgC,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC7F,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACvC,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC;YACzC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,YAAY,CAAC,CAAC;AAC7E,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demo-reset.d.ts","sourceRoot":"","sources":["../../../src/routes/admin/demo-reset.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,QAAA,MAAM,MAAM,4CAAW,CAAC;AA4DxB,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Demo reset endpoint
|
|
3
|
+
* Only available when DEMO_MODE is enabled
|
|
4
|
+
* Allows manual triggering of database reset
|
|
5
|
+
*/
|
|
6
|
+
import { Router } from 'express';
|
|
7
|
+
import { resetDatabase } from '../../db/seed.js';
|
|
8
|
+
import { requireAuth } from '../../middleware/auth.js';
|
|
9
|
+
const router = Router();
|
|
10
|
+
/**
|
|
11
|
+
* @swagger
|
|
12
|
+
* /api/admin/demo-reset:
|
|
13
|
+
* post:
|
|
14
|
+
* summary: Reset demo database
|
|
15
|
+
* description: Resets the database to initial demo state. Only available when DEMO_MODE=true. Requires admin authentication.
|
|
16
|
+
* tags: [Admin]
|
|
17
|
+
* security:
|
|
18
|
+
* - cookieAuth: []
|
|
19
|
+
* - bearerAuth: []
|
|
20
|
+
* responses:
|
|
21
|
+
* 200:
|
|
22
|
+
* description: Database reset completed successfully
|
|
23
|
+
* content:
|
|
24
|
+
* application/json:
|
|
25
|
+
* schema:
|
|
26
|
+
* type: object
|
|
27
|
+
* properties:
|
|
28
|
+
* message:
|
|
29
|
+
* type: string
|
|
30
|
+
* example: "Database reset completed successfully"
|
|
31
|
+
* 403:
|
|
32
|
+
* description: Not authorized (not admin) or DEMO_MODE not enabled
|
|
33
|
+
* 500:
|
|
34
|
+
* description: Internal server error
|
|
35
|
+
*/
|
|
36
|
+
router.post('/', requireAuth(), async (req, res) => {
|
|
37
|
+
try {
|
|
38
|
+
// Only allow in DEMO_MODE
|
|
39
|
+
if (process.env.DEMO_MODE !== 'true') {
|
|
40
|
+
return res.status(403).json({
|
|
41
|
+
error: 'Demo reset is only available when DEMO_MODE is enabled',
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
// Check if user is admin
|
|
45
|
+
const authReq = req;
|
|
46
|
+
if (!authReq.user || !authReq.user.is_admin) {
|
|
47
|
+
return res.status(403).json({ error: 'Admin access required' });
|
|
48
|
+
}
|
|
49
|
+
// Perform reset
|
|
50
|
+
console.log('🔄 Manual database reset triggered by admin');
|
|
51
|
+
await resetDatabase();
|
|
52
|
+
res.json({
|
|
53
|
+
message: 'Database reset completed successfully',
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
console.error('Error resetting database:', error);
|
|
58
|
+
res.status(500).json({
|
|
59
|
+
error: process.env.NODE_ENV === 'production'
|
|
60
|
+
? 'Internal server error'
|
|
61
|
+
: error.message,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
export default router;
|
|
66
|
+
//# sourceMappingURL=demo-reset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demo-reset.js","sourceRoot":"","sources":["../../../src/routes/admin/demo-reset.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAe,MAAM,0BAA0B,CAAC;AAEpE,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;IACjD,IAAI,CAAC;QACH,0BAA0B;QAC1B,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,KAAK,MAAM,EAAE,CAAC;YACrC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBAC1B,KAAK,EAAE,wDAAwD;aAChE,CAAC,CAAC;QACL,CAAC;QAED,yBAAyB;QACzB,MAAM,OAAO,GAAG,GAAkB,CAAC;QACnC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC5C,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;QAClE,CAAC;QAED,gBAAgB;QAChB,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;QAC3D,MAAM,aAAa,EAAE,CAAC;QAEtB,GAAG,CAAC,IAAI,CAAC;YACP,OAAO,EAAE,uCAAuC;SACjD,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;QAClD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACnB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;gBAC1C,CAAC,CAAC,uBAAuB;gBACzB,CAAC,CAAC,KAAK,CAAC,OAAO;SAClB,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../src/routes/admin/settings.ts"],"names":[],"mappings":"AAOA,QAAA,MAAM,MAAM,4CAAW,CAAC;AA2dxB,eAAe,MAAM,CAAC"}
|