@sixthsummit/ship-api 0.0.0-stage → 4.1.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/CHANGELOG.md +605 -0
- package/LICENSE +202 -0
- package/NOTICE +4 -0
- package/README.md +58 -2
- package/cli/commands/add.js +537 -0
- package/cli/commands/contract.js +2 -0
- package/cli/commands/create.js +250 -0
- package/cli/commands/dev.js +227 -0
- package/cli/commands/doctor.js +286 -0
- package/cli/commands/generate.js +937 -0
- package/cli/commands/graph.js +2 -0
- package/cli/commands/migrate-orm.js +1171 -0
- package/cli/commands/update.js +37 -0
- package/cli/ship-api.js +285 -0
- package/lib/app/auth/AuthProvider.d.ts +91 -0
- package/lib/app/auth/AuthProvider.d.ts.map +1 -0
- package/lib/app/auth/AuthProvider.js +13 -0
- package/lib/app/auth/AuthProvider.js.map +1 -0
- package/lib/app/auth/adapters/firebase.d.ts +79 -0
- package/lib/app/auth/adapters/firebase.d.ts.map +1 -0
- package/lib/app/auth/adapters/firebase.js +122 -0
- package/lib/app/auth/adapters/firebase.js.map +1 -0
- package/lib/app/auth/adapters/jwtCookie.d.ts +55 -0
- package/lib/app/auth/adapters/jwtCookie.d.ts.map +1 -0
- package/lib/app/auth/adapters/jwtCookie.js +120 -0
- package/lib/app/auth/adapters/jwtCookie.js.map +1 -0
- package/lib/app/auth/index.d.ts +8 -0
- package/lib/app/auth/index.d.ts.map +1 -0
- package/lib/app/auth/index.js +7 -0
- package/lib/app/auth/index.js.map +1 -0
- package/lib/app/auth/jwt/AuthFlow.d.ts +94 -0
- package/lib/app/auth/jwt/AuthFlow.d.ts.map +1 -0
- package/lib/app/auth/jwt/AuthFlow.js +127 -0
- package/lib/app/auth/jwt/AuthFlow.js.map +1 -0
- package/lib/app/auth/jwt/DrizzleRefreshTokenStore.d.ts +80 -0
- package/lib/app/auth/jwt/DrizzleRefreshTokenStore.d.ts.map +1 -0
- package/lib/app/auth/jwt/DrizzleRefreshTokenStore.js +134 -0
- package/lib/app/auth/jwt/DrizzleRefreshTokenStore.js.map +1 -0
- package/lib/app/auth/jwt/JwtSigner.d.ts +123 -0
- package/lib/app/auth/jwt/JwtSigner.d.ts.map +1 -0
- package/lib/app/auth/jwt/JwtSigner.js +118 -0
- package/lib/app/auth/jwt/JwtSigner.js.map +1 -0
- package/lib/app/auth/jwt/RefreshTokenStore.d.ts +97 -0
- package/lib/app/auth/jwt/RefreshTokenStore.d.ts.map +1 -0
- package/lib/app/auth/jwt/RefreshTokenStore.js +122 -0
- package/lib/app/auth/jwt/RefreshTokenStore.js.map +1 -0
- package/lib/app/auth/permissionDefinition.d.ts +20 -0
- package/lib/app/auth/permissionDefinition.d.ts.map +1 -0
- package/lib/app/auth/permissionDefinition.js +2 -0
- package/lib/app/auth/permissionDefinition.js.map +1 -0
- package/lib/app/context/RequestContext.d.ts +59 -0
- package/lib/app/context/RequestContext.d.ts.map +1 -0
- package/lib/app/context/RequestContext.js +25 -0
- package/lib/app/context/RequestContext.js.map +1 -0
- package/lib/app/db/QueryOptions.d.ts +82 -0
- package/lib/app/db/QueryOptions.d.ts.map +1 -0
- package/lib/app/db/QueryOptions.js +37 -0
- package/lib/app/db/QueryOptions.js.map +1 -0
- package/lib/app/db/baseFields.d.ts +60 -0
- package/lib/app/db/baseFields.d.ts.map +1 -0
- package/lib/app/db/baseFields.js +54 -0
- package/lib/app/db/baseFields.js.map +1 -0
- package/lib/app/db/buildWhere.d.ts +22 -0
- package/lib/app/db/buildWhere.d.ts.map +1 -0
- package/lib/app/db/buildWhere.js +75 -0
- package/lib/app/db/buildWhere.js.map +1 -0
- package/lib/app/db/client.d.ts +111 -0
- package/lib/app/db/client.d.ts.map +1 -0
- package/lib/app/db/client.js +99 -0
- package/lib/app/db/client.js.map +1 -0
- package/lib/app/db/tenantScoped.d.ts +59 -0
- package/lib/app/db/tenantScoped.d.ts.map +1 -0
- package/lib/app/db/tenantScoped.js +54 -0
- package/lib/app/db/tenantScoped.js.map +1 -0
- package/lib/app/db/transaction.d.ts +58 -0
- package/lib/app/db/transaction.d.ts.map +1 -0
- package/lib/app/db/transaction.js +106 -0
- package/lib/app/db/transaction.js.map +1 -0
- package/lib/app/health/HealthCheck.d.ts +121 -0
- package/lib/app/health/HealthCheck.d.ts.map +1 -0
- package/lib/app/health/HealthCheck.js +151 -0
- package/lib/app/health/HealthCheck.js.map +1 -0
- package/lib/app/health/redisHealthCheck.d.ts +14 -0
- package/lib/app/health/redisHealthCheck.d.ts.map +1 -0
- package/lib/app/health/redisHealthCheck.js +21 -0
- package/lib/app/health/redisHealthCheck.js.map +1 -0
- package/lib/app/lifecycle/Bootstrapper.d.ts +92 -0
- package/lib/app/lifecycle/Bootstrapper.d.ts.map +1 -0
- package/lib/app/lifecycle/Bootstrapper.js +99 -0
- package/lib/app/lifecycle/Bootstrapper.js.map +1 -0
- package/lib/app/registry/routes.d.ts +89 -0
- package/lib/app/registry/routes.d.ts.map +1 -0
- package/lib/app/registry/routes.js +72 -0
- package/lib/app/registry/routes.js.map +1 -0
- package/lib/app/services/DrizzleEntityService.d.ts +123 -0
- package/lib/app/services/DrizzleEntityService.d.ts.map +1 -0
- package/lib/app/services/DrizzleEntityService.js +342 -0
- package/lib/app/services/DrizzleEntityService.js.map +1 -0
- package/lib/app/services/RedisProvider.d.ts +52 -0
- package/lib/app/services/RedisProvider.d.ts.map +1 -0
- package/lib/app/services/RedisProvider.js +75 -0
- package/lib/app/services/RedisProvider.js.map +1 -0
- package/lib/app/services/cache/Cache.d.ts +70 -0
- package/lib/app/services/cache/Cache.d.ts.map +1 -0
- package/lib/app/services/cache/Cache.js +18 -0
- package/lib/app/services/cache/Cache.js.map +1 -0
- package/lib/app/services/cache/InMemoryCache.d.ts +35 -0
- package/lib/app/services/cache/InMemoryCache.d.ts.map +1 -0
- package/lib/app/services/cache/InMemoryCache.js +76 -0
- package/lib/app/services/cache/InMemoryCache.js.map +1 -0
- package/lib/app/services/cache/RedisCache.d.ts +99 -0
- package/lib/app/services/cache/RedisCache.d.ts.map +1 -0
- package/lib/app/services/cache/RedisCache.js +150 -0
- package/lib/app/services/cache/RedisCache.js.map +1 -0
- package/lib/app/services/cache/cached.d.ts +30 -0
- package/lib/app/services/cache/cached.d.ts.map +1 -0
- package/lib/app/services/cache/cached.js +38 -0
- package/lib/app/services/cache/cached.js.map +1 -0
- package/lib/app/services/cache/index.d.ts +5 -0
- package/lib/app/services/cache/index.d.ts.map +1 -0
- package/lib/app/services/cache/index.js +4 -0
- package/lib/app/services/cache/index.js.map +1 -0
- package/lib/app/services/cron/defineCron.d.ts +57 -0
- package/lib/app/services/cron/defineCron.d.ts.map +1 -0
- package/lib/app/services/cron/defineCron.js +15 -0
- package/lib/app/services/cron/defineCron.js.map +1 -0
- package/lib/app/services/cron/index.d.ts +2 -0
- package/lib/app/services/cron/index.d.ts.map +1 -0
- package/lib/app/services/cron/index.js +2 -0
- package/lib/app/services/cron/index.js.map +1 -0
- package/lib/app/services/hooks/LifecycleHooks.d.ts +61 -0
- package/lib/app/services/hooks/LifecycleHooks.d.ts.map +1 -0
- package/lib/app/services/hooks/LifecycleHooks.js +85 -0
- package/lib/app/services/hooks/LifecycleHooks.js.map +1 -0
- package/lib/app/services/jobs/JobsManager.d.ts +67 -0
- package/lib/app/services/jobs/JobsManager.d.ts.map +1 -0
- package/lib/app/services/jobs/JobsManager.js +121 -0
- package/lib/app/services/jobs/JobsManager.js.map +1 -0
- package/lib/app/services/jobs/bullBoard.d.ts +72 -0
- package/lib/app/services/jobs/bullBoard.d.ts.map +1 -0
- package/lib/app/services/jobs/bullBoard.js +96 -0
- package/lib/app/services/jobs/bullBoard.js.map +1 -0
- package/lib/app/services/jobs/defineJob.d.ts +81 -0
- package/lib/app/services/jobs/defineJob.d.ts.map +1 -0
- package/lib/app/services/jobs/defineJob.js +49 -0
- package/lib/app/services/jobs/defineJob.js.map +1 -0
- package/lib/app/services/jobs/index.d.ts +4 -0
- package/lib/app/services/jobs/index.d.ts.map +1 -0
- package/lib/app/services/jobs/index.js +4 -0
- package/lib/app/services/jobs/index.js.map +1 -0
- package/lib/app/services/rateLimit/InMemorySlidingWindowBackend.d.ts +23 -0
- package/lib/app/services/rateLimit/InMemorySlidingWindowBackend.d.ts.map +1 -0
- package/lib/app/services/rateLimit/InMemorySlidingWindowBackend.js +51 -0
- package/lib/app/services/rateLimit/InMemorySlidingWindowBackend.js.map +1 -0
- package/lib/app/services/rateLimit/RateLimitBackend.d.ts +41 -0
- package/lib/app/services/rateLimit/RateLimitBackend.d.ts.map +1 -0
- package/lib/app/services/rateLimit/RateLimitBackend.js +19 -0
- package/lib/app/services/rateLimit/RateLimitBackend.js.map +1 -0
- package/lib/app/services/rateLimit/RedisSlidingWindowBackend.d.ts +16 -0
- package/lib/app/services/rateLimit/RedisSlidingWindowBackend.d.ts.map +1 -0
- package/lib/app/services/rateLimit/RedisSlidingWindowBackend.js +80 -0
- package/lib/app/services/rateLimit/RedisSlidingWindowBackend.js.map +1 -0
- package/lib/app/services/rateLimit/index.d.ts +4 -0
- package/lib/app/services/rateLimit/index.d.ts.map +1 -0
- package/lib/app/services/rateLimit/index.js +3 -0
- package/lib/app/services/rateLimit/index.js.map +1 -0
- package/lib/app/services/storage/DiskStorageAdapter.d.ts +62 -0
- package/lib/app/services/storage/DiskStorageAdapter.d.ts.map +1 -0
- package/lib/app/services/storage/DiskStorageAdapter.js +295 -0
- package/lib/app/services/storage/DiskStorageAdapter.js.map +1 -0
- package/lib/app/services/storage/GCSStorageAdapter.d.ts +44 -0
- package/lib/app/services/storage/GCSStorageAdapter.d.ts.map +1 -0
- package/lib/app/services/storage/GCSStorageAdapter.js +133 -0
- package/lib/app/services/storage/GCSStorageAdapter.js.map +1 -0
- package/lib/app/services/storage/S3StorageAdapter.d.ts +57 -0
- package/lib/app/services/storage/S3StorageAdapter.d.ts.map +1 -0
- package/lib/app/services/storage/S3StorageAdapter.js +162 -0
- package/lib/app/services/storage/S3StorageAdapter.js.map +1 -0
- package/lib/app/services/storage/StorageService.d.ts +88 -0
- package/lib/app/services/storage/StorageService.d.ts.map +1 -0
- package/lib/app/services/storage/StorageService.js +18 -0
- package/lib/app/services/storage/StorageService.js.map +1 -0
- package/lib/app/services/storage/index.d.ts +5 -0
- package/lib/app/services/storage/index.d.ts.map +1 -0
- package/lib/app/services/storage/index.js +4 -0
- package/lib/app/services/storage/index.js.map +1 -0
- package/lib/app/utils/ContextValidators.d.ts +46 -0
- package/lib/app/utils/ContextValidators.d.ts.map +1 -0
- package/lib/app/utils/ContextValidators.js +81 -0
- package/lib/app/utils/ContextValidators.js.map +1 -0
- package/lib/app/utils/defineEnv.d.ts +80 -0
- package/lib/app/utils/defineEnv.d.ts.map +1 -0
- package/lib/app/utils/defineEnv.js +95 -0
- package/lib/app/utils/defineEnv.js.map +1 -0
- package/lib/client.d.ts +139 -0
- package/lib/client.d.ts.map +1 -0
- package/lib/client.js +98 -0
- package/lib/client.js.map +1 -0
- package/lib/contract/application.d.ts +3 -0
- package/lib/contract/application.d.ts.map +1 -0
- package/lib/contract/application.js +2 -0
- package/lib/contract/application.js.map +1 -0
- package/lib/contract/client.d.ts +3 -0
- package/lib/contract/client.d.ts.map +1 -0
- package/lib/contract/client.js +3 -0
- package/lib/contract/client.js.map +1 -0
- package/lib/contract/index.d.ts +3 -0
- package/lib/contract/index.d.ts.map +1 -0
- package/lib/contract/index.js +3 -0
- package/lib/contract/index.js.map +1 -0
- package/lib/contract/manifest.d.ts +3 -0
- package/lib/contract/manifest.d.ts.map +1 -0
- package/lib/contract/manifest.js +2 -0
- package/lib/contract/manifest.js.map +1 -0
- package/lib/contract/openapi.d.ts +3 -0
- package/lib/contract/openapi.d.ts.map +1 -0
- package/lib/contract/openapi.js +3 -0
- package/lib/contract/openapi.js.map +1 -0
- package/lib/contract/project.d.ts +3 -0
- package/lib/contract/project.d.ts.map +1 -0
- package/lib/contract/project.js +3 -0
- package/lib/contract/project.js.map +1 -0
- package/lib/contract/schema.d.ts +3 -0
- package/lib/contract/schema.d.ts.map +1 -0
- package/lib/contract/schema.js +3 -0
- package/lib/contract/schema.js.map +1 -0
- package/lib/drizzle/index.d.ts +3 -0
- package/lib/drizzle/index.d.ts.map +1 -0
- package/lib/drizzle/index.js +3 -0
- package/lib/drizzle/index.js.map +1 -0
- package/lib/hono/auth.d.ts +6 -0
- package/lib/hono/auth.d.ts.map +1 -0
- package/lib/hono/auth.js +54 -0
- package/lib/hono/auth.js.map +1 -0
- package/lib/hono/index.d.ts +4 -0
- package/lib/hono/index.d.ts.map +1 -0
- package/lib/hono/index.js +4 -0
- package/lib/hono/index.js.map +1 -0
- package/lib/http/app/createApp.d.ts +132 -0
- package/lib/http/app/createApp.d.ts.map +1 -0
- package/lib/http/app/createApp.js +215 -0
- package/lib/http/app/createApp.js.map +1 -0
- package/lib/http/app/devRoutes.d.ts +31 -0
- package/lib/http/app/devRoutes.d.ts.map +1 -0
- package/lib/http/app/devRoutes.js +145 -0
- package/lib/http/app/devRoutes.js.map +1 -0
- package/lib/http/app/errors.d.ts +45 -0
- package/lib/http/app/errors.d.ts.map +1 -0
- package/lib/http/app/errors.js +93 -0
- package/lib/http/app/errors.js.map +1 -0
- package/lib/http/app/health.d.ts +66 -0
- package/lib/http/app/health.d.ts.map +1 -0
- package/lib/http/app/health.js +104 -0
- package/lib/http/app/health.js.map +1 -0
- package/lib/http/errors/AppError.d.ts +10 -0
- package/lib/http/errors/AppError.d.ts.map +1 -0
- package/lib/http/errors/AppError.js +19 -0
- package/lib/http/errors/AppError.js.map +1 -0
- package/lib/http/errors/AuthenticationError.d.ts +8 -0
- package/lib/http/errors/AuthenticationError.d.ts.map +1 -0
- package/lib/http/errors/AuthenticationError.js +10 -0
- package/lib/http/errors/AuthenticationError.js.map +1 -0
- package/lib/http/errors/AuthorizationError.d.ts +8 -0
- package/lib/http/errors/AuthorizationError.d.ts.map +1 -0
- package/lib/http/errors/AuthorizationError.js +10 -0
- package/lib/http/errors/AuthorizationError.js.map +1 -0
- package/lib/http/errors/BadRequestError.d.ts +8 -0
- package/lib/http/errors/BadRequestError.d.ts.map +1 -0
- package/lib/http/errors/BadRequestError.js +10 -0
- package/lib/http/errors/BadRequestError.js.map +1 -0
- package/lib/http/errors/ConflictError.d.ts +8 -0
- package/lib/http/errors/ConflictError.d.ts.map +1 -0
- package/lib/http/errors/ConflictError.js +10 -0
- package/lib/http/errors/ConflictError.js.map +1 -0
- package/lib/http/errors/InternalServerError.d.ts +8 -0
- package/lib/http/errors/InternalServerError.d.ts.map +1 -0
- package/lib/http/errors/InternalServerError.js +10 -0
- package/lib/http/errors/InternalServerError.js.map +1 -0
- package/lib/http/errors/NotFoundError.d.ts +8 -0
- package/lib/http/errors/NotFoundError.d.ts.map +1 -0
- package/lib/http/errors/NotFoundError.js +10 -0
- package/lib/http/errors/NotFoundError.js.map +1 -0
- package/lib/http/errors/RateLimitError.d.ts +13 -0
- package/lib/http/errors/RateLimitError.d.ts.map +1 -0
- package/lib/http/errors/RateLimitError.js +16 -0
- package/lib/http/errors/RateLimitError.js.map +1 -0
- package/lib/http/errors/ServiceUnavailableError.d.ts +8 -0
- package/lib/http/errors/ServiceUnavailableError.d.ts.map +1 -0
- package/lib/http/errors/ServiceUnavailableError.js +10 -0
- package/lib/http/errors/ServiceUnavailableError.js.map +1 -0
- package/lib/http/errors/ValidationError.d.ts +9 -0
- package/lib/http/errors/ValidationError.d.ts.map +1 -0
- package/lib/http/errors/ValidationError.js +12 -0
- package/lib/http/errors/ValidationError.js.map +1 -0
- package/lib/http/errors/index.d.ts +11 -0
- package/lib/http/errors/index.d.ts.map +1 -0
- package/lib/http/errors/index.js +12 -0
- package/lib/http/errors/index.js.map +1 -0
- package/lib/http/middleware/apiKey.d.ts +9 -0
- package/lib/http/middleware/apiKey.d.ts.map +1 -0
- package/lib/http/middleware/apiKey.js +71 -0
- package/lib/http/middleware/apiKey.js.map +1 -0
- package/lib/http/middleware/csrf.d.ts +63 -0
- package/lib/http/middleware/csrf.d.ts.map +1 -0
- package/lib/http/middleware/csrf.js +169 -0
- package/lib/http/middleware/csrf.js.map +1 -0
- package/lib/http/middleware/httpLogger.d.ts +39 -0
- package/lib/http/middleware/httpLogger.d.ts.map +1 -0
- package/lib/http/middleware/httpLogger.js +118 -0
- package/lib/http/middleware/httpLogger.js.map +1 -0
- package/lib/http/middleware/idempotency.d.ts +48 -0
- package/lib/http/middleware/idempotency.d.ts.map +1 -0
- package/lib/http/middleware/idempotency.js +180 -0
- package/lib/http/middleware/idempotency.js.map +1 -0
- package/lib/http/middleware/rateLimit.d.ts +105 -0
- package/lib/http/middleware/rateLimit.d.ts.map +1 -0
- package/lib/http/middleware/rateLimit.js +84 -0
- package/lib/http/middleware/rateLimit.js.map +1 -0
- package/lib/http/middleware/requireAuth.d.ts +58 -0
- package/lib/http/middleware/requireAuth.d.ts.map +1 -0
- package/lib/http/middleware/requireAuth.js +63 -0
- package/lib/http/middleware/requireAuth.js.map +1 -0
- package/lib/http/middleware/requirePermission.d.ts +23 -0
- package/lib/http/middleware/requirePermission.d.ts.map +1 -0
- package/lib/http/middleware/requirePermission.js +50 -0
- package/lib/http/middleware/requirePermission.js.map +1 -0
- package/lib/http/middleware/resolveTenant.d.ts +41 -0
- package/lib/http/middleware/resolveTenant.d.ts.map +1 -0
- package/lib/http/middleware/resolveTenant.js +17 -0
- package/lib/http/middleware/resolveTenant.js.map +1 -0
- package/lib/http/streaming/sse.d.ts +31 -0
- package/lib/http/streaming/sse.d.ts.map +1 -0
- package/lib/http/streaming/sse.js +11 -0
- package/lib/http/streaming/sse.js.map +1 -0
- package/lib/http/streaming/streamLLM.d.ts +94 -0
- package/lib/http/streaming/streamLLM.d.ts.map +1 -0
- package/lib/http/streaming/streamLLM.js +94 -0
- package/lib/http/streaming/streamLLM.js.map +1 -0
- package/lib/http/utils/authCookies.d.ts +74 -0
- package/lib/http/utils/authCookies.d.ts.map +1 -0
- package/lib/http/utils/authCookies.js +102 -0
- package/lib/http/utils/authCookies.js.map +1 -0
- package/lib/http/utils/clientIp.d.ts +85 -0
- package/lib/http/utils/clientIp.d.ts.map +1 -0
- package/lib/http/utils/clientIp.js +249 -0
- package/lib/http/utils/clientIp.js.map +1 -0
- package/lib/http/utils/index.d.ts +4 -0
- package/lib/http/utils/index.d.ts.map +1 -0
- package/lib/http/utils/index.js +5 -0
- package/lib/http/utils/index.js.map +1 -0
- package/lib/http/utils/metaTags.d.ts +49 -0
- package/lib/http/utils/metaTags.d.ts.map +1 -0
- package/lib/http/utils/metaTags.js +32 -0
- package/lib/http/utils/metaTags.js.map +1 -0
- package/lib/http/utils/publicSuffix.d.ts +34 -0
- package/lib/http/utils/publicSuffix.d.ts.map +1 -0
- package/lib/http/utils/publicSuffix.js +276 -0
- package/lib/http/utils/publicSuffix.js.map +1 -0
- package/lib/http/utils/uploads.d.ts +92 -0
- package/lib/http/utils/uploads.d.ts.map +1 -0
- package/lib/http/utils/uploads.js +126 -0
- package/lib/http/utils/uploads.js.map +1 -0
- package/lib/http/utils/validate.d.ts +41 -0
- package/lib/http/utils/validate.d.ts.map +1 -0
- package/lib/http/utils/validate.js +55 -0
- package/lib/http/utils/validate.js.map +1 -0
- package/lib/http/utils/webhooks.d.ts +63 -0
- package/lib/http/utils/webhooks.d.ts.map +1 -0
- package/lib/http/utils/webhooks.js +133 -0
- package/lib/http/utils/webhooks.js.map +1 -0
- package/lib/http/ws/auth.d.ts +46 -0
- package/lib/http/ws/auth.d.ts.map +1 -0
- package/lib/http/ws/auth.js +123 -0
- package/lib/http/ws/auth.js.map +1 -0
- package/lib/index.d.ts +80 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +61 -0
- package/lib/index.js.map +1 -0
- package/lib/kernel/index.d.ts +3 -0
- package/lib/kernel/index.d.ts.map +1 -0
- package/lib/kernel/index.js +3 -0
- package/lib/kernel/index.js.map +1 -0
- package/lib/libraries/.gitkeep +0 -0
- package/lib/libraries/ai/CHANGELOG.md +17 -0
- package/lib/libraries/ai/README.md +164 -0
- package/lib/libraries/ai/adapters/AnthropicAdapter.ts +382 -0
- package/lib/libraries/ai/adapters/LLMProvider.ts +76 -0
- package/lib/libraries/ai/adapters/OpenAIAdapter.ts +466 -0
- package/lib/libraries/ai/experimental/index.ts +20 -0
- package/lib/libraries/ai/index.ts +128 -0
- package/lib/libraries/ai/library.json +19 -0
- package/lib/libraries/ai/loop/agentLoop.ts +377 -0
- package/lib/libraries/ai/prompts/definePrompt.ts +0 -0
- package/lib/libraries/ai/rag/retrieveAndAnswer.ts +177 -0
- package/lib/libraries/ai/streaming/streamLLM.ts +94 -0
- package/lib/libraries/ai/structured/completeStructured.ts +143 -0
- package/lib/libraries/ai/tokens/Tokenizer.ts +216 -0
- package/lib/libraries/ai/tools/defineTool.ts +208 -0
- package/lib/libraries/ai/types.ts +260 -0
- package/lib/libraries/chunking/ChunkingService.ts +103 -0
- package/lib/libraries/chunking/README.md +104 -0
- package/lib/libraries/chunking/docs/api-reference.md +549 -0
- package/lib/libraries/chunking/docs/best-practices.md +321 -0
- package/lib/libraries/chunking/docs/code-organization.md +538 -0
- package/lib/libraries/chunking/docs/configuration.md +418 -0
- package/lib/libraries/chunking/docs/index.md +236 -0
- package/lib/libraries/chunking/docs/quick-start.md +298 -0
- package/lib/libraries/chunking/docs/strategies.md +407 -0
- package/lib/libraries/chunking/docs/summary.md +258 -0
- package/lib/libraries/chunking/docs/troubleshooting.md +527 -0
- package/lib/libraries/chunking/index.ts +17 -0
- package/lib/libraries/chunking/library.json +16 -0
- package/lib/libraries/chunking/strategies/ChunkingStrategy.ts +13 -0
- package/lib/libraries/chunking/strategies/FixedLengthChunkingStrategy.ts +88 -0
- package/lib/libraries/chunking/strategies/SemanticChunkingStrategy.ts +389 -0
- package/lib/libraries/chunking/strategies/SlidingWindowChunkingStrategy.ts +258 -0
- package/lib/libraries/chunking/types/index.ts +63 -0
- package/lib/libraries/email/EmailService.ts +591 -0
- package/lib/libraries/email/README.md +777 -0
- package/lib/libraries/email/TemplateRegistry.ts +148 -0
- package/lib/libraries/email/TemplateRenderer.ts +273 -0
- package/lib/libraries/email/index.ts +4 -0
- package/lib/libraries/email/initializeEmailService.ts +60 -0
- package/lib/libraries/email/library.json +12 -0
- package/lib/libraries/email/types/EmailAddress.ts +4 -0
- package/lib/libraries/email/types/EmailAttachment.ts +11 -0
- package/lib/libraries/email/types/EmailTag.ts +9 -0
- package/lib/libraries/email/types/EmailTemplate.ts +124 -0
- package/lib/libraries/email/types/SendBatchEmailsOptions.ts +9 -0
- package/lib/libraries/email/types/SendBatchEmailsResult.ts +9 -0
- package/lib/libraries/email/types/SendEmailOptions.ts +33 -0
- package/lib/libraries/email/types/SendEmailResult.ts +9 -0
- package/lib/libraries/email/types/index.ts +8 -0
- package/lib/libraries/weaviate/QueryBuilder.ts +292 -0
- package/lib/libraries/weaviate/README.md +284 -0
- package/lib/libraries/weaviate/Weaviate.ts +1419 -0
- package/lib/libraries/weaviate/WeaviateConfig.ts +268 -0
- package/lib/libraries/weaviate/docs/.gitkeep +1 -0
- package/lib/libraries/weaviate/docs/API_REFERENCE.md +1067 -0
- package/lib/libraries/weaviate/docs/CONFIGURATION.md +320 -0
- package/lib/libraries/weaviate/docs/ERROR_HANDLING.md +271 -0
- package/lib/libraries/weaviate/docs/MULTI_TENANCY.md +348 -0
- package/lib/libraries/weaviate/docs/PERFORMANCE.md +602 -0
- package/lib/libraries/weaviate/docs/PLUGIN_DEVELOPMENT.md +547 -0
- package/lib/libraries/weaviate/docs/QUICK_START.md +443 -0
- package/lib/libraries/weaviate/docs/README.md +269 -0
- package/lib/libraries/weaviate/docs/SCHEMA_GUIDE.md +630 -0
- package/lib/libraries/weaviate/docs/WEAVIATE_README.md +520 -0
- package/lib/libraries/weaviate/errors/WeaviateError.ts +92 -0
- package/lib/libraries/weaviate/errors/index.ts +1 -0
- package/lib/libraries/weaviate/index.ts +35 -0
- package/lib/libraries/weaviate/library.json +26 -0
- package/lib/libraries/weaviate/plugins/index.ts +2 -0
- package/lib/libraries/weaviate/schemas/SchemaRegistry.ts +284 -0
- package/lib/libraries/weaviate/schemas/index.ts +2 -0
- package/lib/libraries/weaviate/types/BM25SearchOptions.ts +9 -0
- package/lib/libraries/weaviate/types/ExtendedWeaviateClient.ts +7 -0
- package/lib/libraries/weaviate/types/HybridSearchOptions.ts +11 -0
- package/lib/libraries/weaviate/types/MultiTenancy.ts +81 -0
- package/lib/libraries/weaviate/types/Plugin.ts +17 -0
- package/lib/libraries/weaviate/types/SchemaConfig.ts +25 -0
- package/lib/libraries/weaviate/types/SearchMethod.ts +8 -0
- package/lib/libraries/weaviate/types/SearchOptions.ts +16 -0
- package/lib/libraries/weaviate/types/SearchRequest.ts +19 -0
- package/lib/libraries/weaviate/types/SearchResult.ts +16 -0
- package/lib/libraries/weaviate/types/SearchableField.ts +87 -0
- package/lib/libraries/weaviate/types/VectorIndexConfig.ts +19 -0
- package/lib/libraries/weaviate/types/VectorSearchOptions.ts +18 -0
- package/lib/libraries/weaviate/types/VectorizerConfig.ts +8 -0
- package/lib/libraries/weaviate/types/index.ts +29 -0
- package/lib/libraries/weaviate/utils/TenantContextManager.ts +94 -0
- package/lib/modules/accounts/index.ts +47 -0
- package/lib/modules/accounts/module.json +15 -0
- package/lib/modules/accounts/permissions.ts +33 -0
- package/lib/modules/accounts/routes.ts +200 -0
- package/lib/modules/accounts/schema.ts +219 -0
- package/lib/modules/accounts/services/AccountService.ts +44 -0
- package/lib/modules/accounts/validation/schemas.ts +70 -0
- package/lib/modules/oauth/adapters/GmailOAuthAdapter.ts +35 -0
- package/lib/modules/oauth/adapters/GoogleOAuthAdapter.ts +278 -0
- package/lib/modules/oauth/adapters/MicrosoftOAuthAdapter.ts +269 -0
- package/lib/modules/oauth/adapters/MockOAuthAdapter.ts +138 -0
- package/lib/modules/oauth/adapters/OAuthAdapter.ts +211 -0
- package/lib/modules/oauth/adapters/OAuthAdapterRegistry.ts +77 -0
- package/lib/modules/oauth/adapters/OutlookOAuthAdapter.ts +38 -0
- package/lib/modules/oauth/index.ts +79 -0
- package/lib/modules/oauth/module.json +23 -0
- package/lib/modules/oauth/permissions.ts +39 -0
- package/lib/modules/oauth/routes.ts +497 -0
- package/lib/modules/oauth/schema.ts +127 -0
- package/lib/modules/oauth/services/OAuthConnectionService.ts +147 -0
- package/lib/modules/oauth/state.ts +234 -0
- package/lib/modules/oauth/stateJtiCache.ts +85 -0
- package/lib/modules/oauth/verifyIdToken.ts +178 -0
- package/lib/modules/outbox/EventEmitter.ts +106 -0
- package/lib/modules/outbox/OutboxDrainer.ts +163 -0
- package/lib/modules/outbox/handlers/EventHandler.ts +115 -0
- package/lib/modules/outbox/index.ts +43 -0
- package/lib/modules/outbox/module.json +15 -0
- package/lib/modules/outbox/permissions.ts +36 -0
- package/lib/modules/outbox/routes.ts +219 -0
- package/lib/modules/outbox/schema.ts +207 -0
- package/lib/modules/outbox/services/OutboxEventService.ts +223 -0
- package/lib/observability/logger.d.ts +30 -0
- package/lib/observability/logger.d.ts.map +1 -0
- package/lib/observability/logger.js +110 -0
- package/lib/observability/logger.js.map +1 -0
- package/lib/observability/metrics.d.ts +3 -0
- package/lib/observability/metrics.d.ts.map +1 -0
- package/lib/observability/metrics.js +3 -0
- package/lib/observability/metrics.js.map +1 -0
- package/lib/observability/otel.d.ts +3 -0
- package/lib/observability/otel.d.ts.map +1 -0
- package/lib/observability/otel.js +3 -0
- package/lib/observability/otel.js.map +1 -0
- package/lib/observability/safeErrorFields.d.ts +14 -0
- package/lib/observability/safeErrorFields.d.ts.map +1 -0
- package/lib/observability/safeErrorFields.js +14 -0
- package/lib/observability/safeErrorFields.js.map +1 -0
- package/lib/observability/tracing.d.ts +3 -0
- package/lib/observability/tracing.d.ts.map +1 -0
- package/lib/observability/tracing.js +3 -0
- package/lib/observability/tracing.js.map +1 -0
- package/lib/package.json +4 -0
- package/lib/testing.d.ts +3 -0
- package/lib/testing.d.ts.map +1 -0
- package/lib/testing.js +3 -0
- package/lib/testing.js.map +1 -0
- package/package.json +193 -3
- package/templates/default/.claude/agents/qa-brief.md +106 -0
- package/templates/default/.claude/commands/sherpa-brief.md +23 -0
- package/templates/default/.cursor/rules/api.mdc +80 -0
- package/templates/default/.cursor/rules/commits.mdc +88 -0
- package/templates/default/.cursor/rules/security.mdc +92 -0
- package/templates/default/.cursor/rules/testing.mdc +123 -0
- package/templates/default/.cursor/rules/typescript.mdc +86 -0
- package/templates/default/.env.example +79 -0
- package/templates/default/.github/workflows/sherpa-brief.yml +180 -0
- package/templates/default/AGENTS.md +166 -0
- package/templates/default/CLAUDE.md +17 -0
- package/templates/default/README.md +97 -0
- package/templates/default/_gitignore +27 -0
- package/templates/default/docker-compose.yml +83 -0
- package/templates/default/drizzle.config.ts +34 -0
- package/templates/default/eslint.config.mjs +106 -0
- package/templates/default/package.json +57 -0
- package/templates/default/ship-api.config.ts +21 -0
- package/templates/default/src/client.ts +34 -0
- package/templates/default/src/config/modules.ts +23 -0
- package/templates/default/src/db/schema.ts +26 -0
- package/templates/default/src/environment.ts +81 -0
- package/templates/default/src/index.test.ts +53 -0
- package/templates/default/src/index.ts +11 -0
- package/templates/default/src/instrumentation.ts +13 -0
- package/templates/default/src/server.ts +90 -0
- package/templates/default/tsconfig.json +24 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { AuthClaims, AuthenticatedAccount, AuthProvider, AuthProviderContext, AuthVerifyResult } from "../AuthProvider.js";
|
|
2
|
+
import type { JwtSigner } from "../jwt/JwtSigner.js";
|
|
3
|
+
/**
|
|
4
|
+
* `jwtCookieAuth` — `AuthProvider` adapter for the framework's stateless cookie
|
|
5
|
+
* auth flow (the v4.0 default for first-party clients).
|
|
6
|
+
*
|
|
7
|
+
* Plugs into the same `requireAuth({ provider })` middleware that the Firebase
|
|
8
|
+
* adapter does, so internal-only ShipAPI deployments can use cookie auth and
|
|
9
|
+
* external/partner deployments can use Firebase IdTokens (or any v4.x adapter)
|
|
10
|
+
* without changing the middleware contract.
|
|
11
|
+
*
|
|
12
|
+
* Verification flow:
|
|
13
|
+
* 1. Read the access cookie (`ship_access` by default; configurable).
|
|
14
|
+
* 2. Verify the JWS via `JwtSigner.verify()` — signature, expiry, issuer,
|
|
15
|
+
* audience all validated, with `kid`-based key rotation supported.
|
|
16
|
+
* 3. Resolve the domain `Account` via the consumer-supplied `findAccount`
|
|
17
|
+
* callback (mirrors `FirebaseAuthProvider`'s shape).
|
|
18
|
+
*
|
|
19
|
+
* The `claims.subject` is taken from the JWT's `sub` claim — populated by
|
|
20
|
+
* `AuthFlow.issue()` with the `accountId`. Custom claims threaded into the
|
|
21
|
+
* token via `AuthFlow.issue({ claims })` surface in `AuthClaims.metadata`.
|
|
22
|
+
*/
|
|
23
|
+
export interface JwtCookieAuthProviderOptions<TAccount extends AuthenticatedAccount = AuthenticatedAccount> {
|
|
24
|
+
/** The framework's `JwtSigner` (typically obtained from `AuthFlow`). */
|
|
25
|
+
signer: JwtSigner;
|
|
26
|
+
/**
|
|
27
|
+
* Resolve a domain Account from the verified JWT's claims. Mirrors
|
|
28
|
+
* `FirebaseAuthProvider.findAccount` — consumers wire this to their account
|
|
29
|
+
* lookup. Returns `null` if no account exists.
|
|
30
|
+
*/
|
|
31
|
+
findAccount: (accountId: string, claims: AuthClaims) => Promise<TAccount | null>;
|
|
32
|
+
/** Override the access cookie name. Default `"ship_access"`. */
|
|
33
|
+
cookieName?: string;
|
|
34
|
+
/** Provider behavior when no cookie is present. Default `"reject"`. */
|
|
35
|
+
onMissingToken?: "reject" | "next";
|
|
36
|
+
/** Provider behavior when JWT verifies but no account resolves. Default `"reject"`. */
|
|
37
|
+
onUnknownAccount?: "reject" | "create" | "next";
|
|
38
|
+
}
|
|
39
|
+
export declare class JwtCookieAuthProvider<TAccount extends AuthenticatedAccount = AuthenticatedAccount> implements AuthProvider<TAccount> {
|
|
40
|
+
readonly name = "jwt-cookie";
|
|
41
|
+
readonly onMissingToken: "reject" | "next";
|
|
42
|
+
readonly onUnknownAccount: "reject" | "create" | "next";
|
|
43
|
+
private readonly signer;
|
|
44
|
+
private readonly findAccount;
|
|
45
|
+
private readonly cookieName;
|
|
46
|
+
constructor(opts: JwtCookieAuthProviderOptions<TAccount>);
|
|
47
|
+
verify(ctx: AuthProviderContext): Promise<AuthVerifyResult>;
|
|
48
|
+
resolve(claims: AuthClaims): Promise<TAccount | null>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Convenience factory — matches the documented `jwtCookieAuth({ ... })` shape
|
|
52
|
+
* in §F of the plan, parallel to `firebaseAuth({ ... })`.
|
|
53
|
+
*/
|
|
54
|
+
export declare function jwtCookieAuth<TAccount extends AuthenticatedAccount = AuthenticatedAccount>(opts: JwtCookieAuthProviderOptions<TAccount>): JwtCookieAuthProvider<TAccount>;
|
|
55
|
+
//# sourceMappingURL=jwtCookie.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwtCookie.d.ts","sourceRoot":"","sources":["../../../../src/app/auth/adapters/jwtCookie.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,UAAU,EACV,oBAAoB,EACpB,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,4BAA4B,CAC3C,QAAQ,SAAS,oBAAoB,GAAG,oBAAoB;IAE5D,wEAAwE;IACxE,MAAM,EAAE,SAAS,CAAC;IAClB;;;;OAIG;IACH,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IACjF,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,cAAc,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IACnC,uFAAuF;IACvF,gBAAgB,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;CACjD;AAED,qBAAa,qBAAqB,CAAC,QAAQ,SAAS,oBAAoB,GAAG,oBAAoB,CAC7F,YAAW,YAAY,CAAC,QAAQ,CAAC;IAEjC,QAAQ,CAAC,IAAI,gBAAgB;IAC7B,QAAQ,CAAC,cAAc,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC3C,QAAQ,CAAC,gBAAgB,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;IAExD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAwD;IACpF,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAExB,IAAI,EAAE,4BAA4B,CAAC,QAAQ,CAAC;IAQlD,MAAM,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAyB3D,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;CAG5D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,QAAQ,SAAS,oBAAoB,GAAG,oBAAoB,EACxF,IAAI,EAAE,4BAA4B,CAAC,QAAQ,CAAC,GAC3C,qBAAqB,CAAC,QAAQ,CAAC,CAEjC"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { AUTH_COOKIE_NAMES } from "../../../http/utils/authCookies.js";
|
|
2
|
+
export class JwtCookieAuthProvider {
|
|
3
|
+
name = "jwt-cookie";
|
|
4
|
+
onMissingToken;
|
|
5
|
+
onUnknownAccount;
|
|
6
|
+
signer;
|
|
7
|
+
findAccount;
|
|
8
|
+
cookieName;
|
|
9
|
+
constructor(opts) {
|
|
10
|
+
this.signer = opts.signer;
|
|
11
|
+
this.findAccount = opts.findAccount;
|
|
12
|
+
this.cookieName = opts.cookieName ?? AUTH_COOKIE_NAMES.access;
|
|
13
|
+
this.onMissingToken = opts.onMissingToken ?? "reject";
|
|
14
|
+
this.onUnknownAccount = opts.onUnknownAccount ?? "reject";
|
|
15
|
+
}
|
|
16
|
+
async verify(ctx) {
|
|
17
|
+
const token = readCookieFromHeaders(ctx.headers, this.cookieName);
|
|
18
|
+
if (!token) {
|
|
19
|
+
return { ok: false, reason: "missing-token", message: "No access cookie on request" };
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const verified = await this.signer.verify(token);
|
|
23
|
+
const claims = jwtPayloadToClaims(verified.payload);
|
|
24
|
+
return { ok: true, claims };
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
// `JwtSigner.verify` throws `AuthenticationError` with a normalized
|
|
28
|
+
// message. Map common cases back into the `AuthFailureReason` taxonomy
|
|
29
|
+
// so `requireAuth` can format consistently across providers.
|
|
30
|
+
const msg = err.message ?? "Token verification failed";
|
|
31
|
+
if (msg.includes("expired"))
|
|
32
|
+
return { ok: false, reason: "expired-token", message: msg };
|
|
33
|
+
if (msg.includes("revoked"))
|
|
34
|
+
return { ok: false, reason: "revoked-token", message: msg };
|
|
35
|
+
if (msg.includes("kid") || msg.includes("signing key")) {
|
|
36
|
+
return { ok: false, reason: "invalid-token", message: msg };
|
|
37
|
+
}
|
|
38
|
+
if (msg.includes("claim"))
|
|
39
|
+
return { ok: false, reason: "issuer-mismatch", message: msg };
|
|
40
|
+
return { ok: false, reason: "invalid-token", message: msg };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async resolve(claims) {
|
|
44
|
+
return this.findAccount(claims.subject, claims);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Convenience factory — matches the documented `jwtCookieAuth({ ... })` shape
|
|
49
|
+
* in §F of the plan, parallel to `firebaseAuth({ ... })`.
|
|
50
|
+
*/
|
|
51
|
+
export function jwtCookieAuth(opts) {
|
|
52
|
+
return new JwtCookieAuthProvider(opts);
|
|
53
|
+
}
|
|
54
|
+
function readCookieFromHeaders(headers, cookieName) {
|
|
55
|
+
const header = headers["cookie"];
|
|
56
|
+
if (!header)
|
|
57
|
+
return undefined;
|
|
58
|
+
// Minimal parser — Hono's `getCookie` does the same thing but expects a
|
|
59
|
+
// `Context`. We only have raw headers in `AuthProviderContext`, so parse
|
|
60
|
+
// here. Cookies are `name=value; name2=value2` — values may contain `=`
|
|
61
|
+
// for base64url so we split on the first `=` only.
|
|
62
|
+
const target = `${cookieName}=`;
|
|
63
|
+
for (const segment of header.split(";")) {
|
|
64
|
+
const trimmed = segment.trimStart();
|
|
65
|
+
if (trimmed.startsWith(target)) {
|
|
66
|
+
const value = trimmed.slice(target.length);
|
|
67
|
+
// Cookie values are not URL-encoded by `setCookie` for typical tokens
|
|
68
|
+
// (base64url is cookie-safe), but be defensive.
|
|
69
|
+
try {
|
|
70
|
+
return decodeURIComponent(value);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
function jwtPayloadToClaims(payload) {
|
|
80
|
+
const sub = payload.sub;
|
|
81
|
+
if (typeof sub !== "string" || sub.length === 0) {
|
|
82
|
+
throw new Error("JWT missing `sub` claim — refusing to resolve account");
|
|
83
|
+
}
|
|
84
|
+
const claims = {
|
|
85
|
+
subject: sub,
|
|
86
|
+
issuedAt: typeof payload.iat === "number" ? payload.iat : undefined,
|
|
87
|
+
expiresAt: typeof payload.exp === "number" ? payload.exp : undefined,
|
|
88
|
+
};
|
|
89
|
+
if (typeof payload.email === "string")
|
|
90
|
+
claims.email = payload.email;
|
|
91
|
+
if (typeof payload.email_verified === "boolean") {
|
|
92
|
+
claims.emailVerified = payload.email_verified;
|
|
93
|
+
}
|
|
94
|
+
if (typeof payload.name === "string")
|
|
95
|
+
claims.name = payload.name;
|
|
96
|
+
// Pass through extra fields under `metadata.custom` for downstream consumers
|
|
97
|
+
// (e.g., role/tenant claims threaded by AuthFlow.issue({ claims })).
|
|
98
|
+
const standard = new Set([
|
|
99
|
+
"sub",
|
|
100
|
+
"iat",
|
|
101
|
+
"exp",
|
|
102
|
+
"iss",
|
|
103
|
+
"aud",
|
|
104
|
+
"jti",
|
|
105
|
+
"nbf",
|
|
106
|
+
"email",
|
|
107
|
+
"email_verified",
|
|
108
|
+
"name",
|
|
109
|
+
]);
|
|
110
|
+
const custom = {};
|
|
111
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
112
|
+
if (!standard.has(key))
|
|
113
|
+
custom[key] = value;
|
|
114
|
+
}
|
|
115
|
+
if (Object.keys(custom).length > 0) {
|
|
116
|
+
claims.metadata = { custom };
|
|
117
|
+
}
|
|
118
|
+
return claims;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=jwtCookie.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwtCookie.js","sourceRoot":"","sources":["../../../../src/app/auth/adapters/jwtCookie.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAkDvE,MAAM,OAAO,qBAAqB;IAGvB,IAAI,GAAG,YAAY,CAAC;IACpB,cAAc,CAAoB;IAClC,gBAAgB,CAA+B;IAEvC,MAAM,CAAY;IAClB,WAAW,CAAwD;IACnE,UAAU,CAAS;IAEpC,YAAY,IAA4C;QACtD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;QACpC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,iBAAiB,CAAC,MAAM,CAAC;QAC9D,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,IAAI,QAAQ,CAAC;QACtD,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,IAAI,QAAQ,CAAC;IAC5D,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAwB;QACnC,MAAM,KAAK,GAAG,qBAAqB,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAClE,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,6BAA6B,EAAE,CAAC;QACxF,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACjD,MAAM,MAAM,GAAG,kBAAkB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACpD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAC9B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,oEAAoE;YACpE,uEAAuE;YACvE,6DAA6D;YAC7D,MAAM,GAAG,GAAI,GAAa,CAAC,OAAO,IAAI,2BAA2B,CAAC;YAClE,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;YACzF,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;YACzF,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;gBACvD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;YAC9D,CAAC;YACD,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;YACzF,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAkB;QAC9B,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAClD,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,IAA4C;IAE5C,OAAO,IAAI,qBAAqB,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,qBAAqB,CAC5B,OAAqD,EACrD,UAAkB;IAElB,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjC,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,wEAAwE;IACxE,yEAAyE;IACzE,wEAAwE;IACxE,mDAAmD;IACnD,MAAM,MAAM,GAAG,GAAG,UAAU,GAAG,CAAC;IAChC,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;QACpC,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC3C,sEAAsE;YACtE,gDAAgD;YAChD,IAAI,CAAC;gBACH,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC;YACnC,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,kBAAkB,CAAC,OAAgC;IAC1D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IACxB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC3E,CAAC;IACD,MAAM,MAAM,GAAe;QACzB,OAAO,EAAE,GAAG;QACZ,QAAQ,EAAE,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;QACnE,SAAS,EAAE,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;KACrE,CAAC;IACF,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ;QAAE,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IACpE,IAAI,OAAO,OAAO,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;QAChD,MAAM,CAAC,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IAChD,CAAC;IACD,IAAI,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ;QAAE,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAEjE,6EAA6E;IAC7E,qEAAqE;IACrE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC;QACvB,KAAK;QACL,KAAK;QACL,KAAK;QACL,KAAK;QACL,KAAK;QACL,KAAK;QACL,KAAK;QACL,OAAO;QACP,gBAAgB;QAChB,MAAM;KACP,CAAC,CAAC;IACH,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACnD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAC9C,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnC,MAAM,CAAC,QAAQ,GAAG,EAAE,MAAM,EAAE,CAAC;IAC/B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type { AccountResolver, AuthClaims, AuthenticatedAccount, AuthFailureReason, AuthProvider, AuthProviderContext, AuthVerifyResult, } from "./AuthProvider.js";
|
|
2
|
+
export { type FirebaseAuthClaimsExtras, FirebaseAuthProvider, type FirebaseAuthProviderOptions, firebaseAuth, } from "./adapters/firebase.js";
|
|
3
|
+
export { JwtCookieAuthProvider, type JwtCookieAuthProviderOptions, jwtCookieAuth, } from "./adapters/jwtCookie.js";
|
|
4
|
+
export { AuthFlow, type AuthFlowOptions, type AuthTokenPair, type IssueAuthInput, } from "./jwt/AuthFlow.js";
|
|
5
|
+
export { DrizzleRefreshTokenStore, type DrizzleRefreshTokenStoreOptions, } from "./jwt/DrizzleRefreshTokenStore.js";
|
|
6
|
+
export { JwtSigner, type JwtSignerOptions, type JwtSigningKey, type JwtVerificationKey, type SignedToken, type SignTokenOptions, type VerifiedToken, } from "./jwt/JwtSigner.js";
|
|
7
|
+
export { generateRefreshTokenValue, hashRefreshToken, InMemoryRefreshTokenStore, type IssueRefreshTokenInput, type RefreshTokenRecord, type RefreshTokenStore, } from "./jwt/RefreshTokenStore.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/app/auth/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,eAAe,EACf,UAAU,EACV,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,KAAK,wBAAwB,EAC7B,oBAAoB,EACpB,KAAK,2BAA2B,EAChC,YAAY,GACb,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,qBAAqB,EACrB,KAAK,4BAA4B,EACjC,aAAa,GACd,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,QAAQ,EACR,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,wBAAwB,EACxB,KAAK,+BAA+B,GACrC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,SAAS,EACT,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,aAAa,GACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,yBAAyB,EACzB,gBAAgB,EAChB,yBAAyB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,GACvB,MAAM,4BAA4B,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { FirebaseAuthProvider, firebaseAuth, } from "./adapters/firebase.js";
|
|
2
|
+
export { JwtCookieAuthProvider, jwtCookieAuth, } from "./adapters/jwtCookie.js";
|
|
3
|
+
export { AuthFlow, } from "./jwt/AuthFlow.js";
|
|
4
|
+
export { DrizzleRefreshTokenStore, } from "./jwt/DrizzleRefreshTokenStore.js";
|
|
5
|
+
export { JwtSigner, } from "./jwt/JwtSigner.js";
|
|
6
|
+
export { generateRefreshTokenValue, hashRefreshToken, InMemoryRefreshTokenStore, } from "./jwt/RefreshTokenStore.js";
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/app/auth/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAEL,oBAAoB,EAEpB,YAAY,GACb,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,qBAAqB,EAErB,aAAa,GACd,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,QAAQ,GAIT,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,wBAAwB,GAEzB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,SAAS,GAOV,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,yBAAyB,EACzB,gBAAgB,EAChB,yBAAyB,GAI1B,MAAM,4BAA4B,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { JwtSigner, VerifiedToken } from "./JwtSigner.js";
|
|
2
|
+
import { type RefreshTokenStore } from "./RefreshTokenStore.js";
|
|
3
|
+
/**
|
|
4
|
+
* `AuthFlow` — the policy layer that ties `JwtSigner` and `RefreshTokenStore`
|
|
5
|
+
* together.
|
|
6
|
+
*
|
|
7
|
+
* Implements the framework's stateless cookie-auth flow:
|
|
8
|
+
*
|
|
9
|
+
* • **Issue** — sign a short-lived access token and mint+persist a long-
|
|
10
|
+
* lived opaque refresh token. The access JWT carries the account id
|
|
11
|
+
* plus arbitrary custom claims; the refresh value is a 256-bit random
|
|
12
|
+
* string whose SHA-256 hash is stored.
|
|
13
|
+
* • **Verify** — decode and validate an access token via `JwtSigner`. Pure
|
|
14
|
+
* stateless check — no DB hit.
|
|
15
|
+
* • **Rotate** — exchange a presented refresh token for a new pair. The
|
|
16
|
+
* old token's row is marked `replaced_by_id = newRow.id`, all in one
|
|
17
|
+
* transaction. **Reuse detection**: if the presented token's row already
|
|
18
|
+
* has `replacedById` set, the entire chain is revoked and the rotation
|
|
19
|
+
* fails — strong signal of token theft.
|
|
20
|
+
* • **Revoke** — single-token revocation (e.g., logout) and account-wide
|
|
21
|
+
* revocation (e.g., password reset, "sign out everywhere").
|
|
22
|
+
*/
|
|
23
|
+
export interface AuthFlowOptions {
|
|
24
|
+
signer: JwtSigner;
|
|
25
|
+
refreshTokenStore: RefreshTokenStore;
|
|
26
|
+
/** Access-token TTL in seconds. Defaults to 15 minutes. */
|
|
27
|
+
accessTokenTtlSec?: number;
|
|
28
|
+
/** Refresh-token TTL in seconds. Defaults to 30 days. */
|
|
29
|
+
refreshTokenTtlSec?: number;
|
|
30
|
+
}
|
|
31
|
+
export interface IssueAuthInput {
|
|
32
|
+
/** Account ID — written to the access token's `sub` and the refresh row's `accountId`. */
|
|
33
|
+
accountId: string;
|
|
34
|
+
/** Optional custom claims on the access token. */
|
|
35
|
+
claims?: Record<string, unknown>;
|
|
36
|
+
/** Audit context — User-Agent and IP are persisted on the refresh row. */
|
|
37
|
+
userAgent?: string;
|
|
38
|
+
ip?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface AuthTokenPair {
|
|
41
|
+
/** Compact JWS access token. */
|
|
42
|
+
accessToken: string;
|
|
43
|
+
/** Opaque refresh token (raw, base64url-encoded random bytes). */
|
|
44
|
+
refreshToken: string;
|
|
45
|
+
/** Access-token expiry (epoch seconds). */
|
|
46
|
+
accessTokenExpiresAt: number;
|
|
47
|
+
/** Refresh-token expiry (epoch seconds). */
|
|
48
|
+
refreshTokenExpiresAt: number;
|
|
49
|
+
/** Refresh row's id — useful for log correlation, never sent to clients. */
|
|
50
|
+
refreshTokenId: string;
|
|
51
|
+
}
|
|
52
|
+
export declare class AuthFlow {
|
|
53
|
+
private readonly signer;
|
|
54
|
+
private readonly store;
|
|
55
|
+
private readonly accessTtlSec;
|
|
56
|
+
private readonly refreshTtlSec;
|
|
57
|
+
constructor(opts: AuthFlowOptions);
|
|
58
|
+
/**
|
|
59
|
+
* Issue a fresh access+refresh pair. Used at login and at first sign-in
|
|
60
|
+
* after a successful third-party auth (e.g., OAuth callback).
|
|
61
|
+
*/
|
|
62
|
+
issue(input: IssueAuthInput): Promise<AuthTokenPair>;
|
|
63
|
+
/**
|
|
64
|
+
* Verify an access token. Stateless — does not touch the refresh-token
|
|
65
|
+
* store. Throws `AuthenticationError` on signature, expiry, or claim
|
|
66
|
+
* validation failure.
|
|
67
|
+
*/
|
|
68
|
+
verifyAccess(token: string): Promise<VerifiedToken>;
|
|
69
|
+
/**
|
|
70
|
+
* Exchange a presented refresh token for a new pair. **Reuse detection**:
|
|
71
|
+
* if the row is already revoked OR already has `replacedById` set, the
|
|
72
|
+
* entire chain is revoked and the call throws. This is a load-bearing
|
|
73
|
+
* security property — a stolen-and-then-original-also-presented refresh
|
|
74
|
+
* token kills the session for both attacker and legitimate user.
|
|
75
|
+
*/
|
|
76
|
+
rotate(presentedRefreshToken: string, audit?: {
|
|
77
|
+
userAgent?: string;
|
|
78
|
+
ip?: string;
|
|
79
|
+
}): Promise<AuthTokenPair>;
|
|
80
|
+
/**
|
|
81
|
+
* Revoke a single refresh token. Idempotent — already-revoked tokens are
|
|
82
|
+
* a no-op. Used at logout. The call is forgiving by design: an attacker
|
|
83
|
+
* presenting an unknown token shouldn't get a different response from
|
|
84
|
+
* one presenting a valid token.
|
|
85
|
+
*/
|
|
86
|
+
revoke(presentedRefreshToken: string): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Revoke every active refresh token for an account. Used at password
|
|
89
|
+
* reset, "sign out everywhere", and admin-driven session termination.
|
|
90
|
+
* Returns the number of tokens revoked for log correlation.
|
|
91
|
+
*/
|
|
92
|
+
revokeAccount(accountId: string): Promise<number>;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=AuthFlow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthFlow.d.ts","sourceRoot":"","sources":["../../../../src/app/auth/jwt/AuthFlow.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,wBAAwB,CAAC;AAEhC;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,SAAS,CAAC;IAClB,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,2DAA2D;IAC3D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yDAAyD;IACzD,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,0FAA0F;IAC1F,SAAS,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,gCAAgC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,YAAY,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,oBAAoB,EAAE,MAAM,CAAC;IAC7B,4CAA4C;IAC5C,qBAAqB,EAAE,MAAM,CAAC;IAC9B,4EAA4E;IAC5E,cAAc,EAAE,MAAM,CAAC;CACxB;AAKD,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoB;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;gBAE3B,IAAI,EAAE,eAAe;IAOjC;;;OAGG;IACG,KAAK,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IA4B1D;;;;OAIG;IACG,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAIzD;;;;;;OAMG;IACG,MAAM,CACV,qBAAqB,EAAE,MAAM,EAC7B,KAAK,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAO,GAC9C,OAAO,CAAC,aAAa,CAAC;IAqDzB;;;;;OAKG;IACG,MAAM,CAAC,qBAAqB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ1D;;;;OAIG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAGxD"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { AuthenticationError } from "../../../http/errors/AuthenticationError.js";
|
|
2
|
+
import { generateRefreshTokenValue, hashRefreshToken, } from "./RefreshTokenStore.js";
|
|
3
|
+
const DEFAULT_ACCESS_TTL_SEC = 15 * 60;
|
|
4
|
+
const DEFAULT_REFRESH_TTL_SEC = 30 * 24 * 60 * 60;
|
|
5
|
+
export class AuthFlow {
|
|
6
|
+
signer;
|
|
7
|
+
store;
|
|
8
|
+
accessTtlSec;
|
|
9
|
+
refreshTtlSec;
|
|
10
|
+
constructor(opts) {
|
|
11
|
+
this.signer = opts.signer;
|
|
12
|
+
this.store = opts.refreshTokenStore;
|
|
13
|
+
this.accessTtlSec = opts.accessTokenTtlSec ?? DEFAULT_ACCESS_TTL_SEC;
|
|
14
|
+
this.refreshTtlSec = opts.refreshTokenTtlSec ?? DEFAULT_REFRESH_TTL_SEC;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Issue a fresh access+refresh pair. Used at login and at first sign-in
|
|
18
|
+
* after a successful third-party auth (e.g., OAuth callback).
|
|
19
|
+
*/
|
|
20
|
+
async issue(input) {
|
|
21
|
+
const access = await this.signer.sign({
|
|
22
|
+
subject: input.accountId,
|
|
23
|
+
ttlSec: this.accessTtlSec,
|
|
24
|
+
claims: input.claims,
|
|
25
|
+
});
|
|
26
|
+
const refreshRaw = generateRefreshTokenValue();
|
|
27
|
+
const refreshHash = hashRefreshToken(refreshRaw);
|
|
28
|
+
const refreshExpiresAt = new Date((Math.floor(Date.now() / 1000) + this.refreshTtlSec) * 1000);
|
|
29
|
+
const refreshRow = await this.store.issue({
|
|
30
|
+
accountId: input.accountId,
|
|
31
|
+
tokenHash: refreshHash,
|
|
32
|
+
expiresAt: refreshExpiresAt,
|
|
33
|
+
userAgent: input.userAgent,
|
|
34
|
+
issuedFromIp: input.ip,
|
|
35
|
+
});
|
|
36
|
+
return {
|
|
37
|
+
accessToken: access.token,
|
|
38
|
+
refreshToken: refreshRaw,
|
|
39
|
+
accessTokenExpiresAt: access.expiresAt,
|
|
40
|
+
refreshTokenExpiresAt: Math.floor(refreshExpiresAt.getTime() / 1000),
|
|
41
|
+
refreshTokenId: refreshRow.id,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Verify an access token. Stateless — does not touch the refresh-token
|
|
46
|
+
* store. Throws `AuthenticationError` on signature, expiry, or claim
|
|
47
|
+
* validation failure.
|
|
48
|
+
*/
|
|
49
|
+
async verifyAccess(token) {
|
|
50
|
+
return this.signer.verify(token);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Exchange a presented refresh token for a new pair. **Reuse detection**:
|
|
54
|
+
* if the row is already revoked OR already has `replacedById` set, the
|
|
55
|
+
* entire chain is revoked and the call throws. This is a load-bearing
|
|
56
|
+
* security property — a stolen-and-then-original-also-presented refresh
|
|
57
|
+
* token kills the session for both attacker and legitimate user.
|
|
58
|
+
*/
|
|
59
|
+
async rotate(presentedRefreshToken, audit = {}) {
|
|
60
|
+
const tokenHash = hashRefreshToken(presentedRefreshToken);
|
|
61
|
+
const row = await this.store.findByHash(tokenHash);
|
|
62
|
+
if (!row) {
|
|
63
|
+
throw new AuthenticationError("Refresh token invalid");
|
|
64
|
+
}
|
|
65
|
+
if (row.revokedAt) {
|
|
66
|
+
// Revoked tokens that get re-presented are a theft signal too — kill the chain.
|
|
67
|
+
await this.store.revokeChain(row.id);
|
|
68
|
+
throw new AuthenticationError("Refresh token revoked");
|
|
69
|
+
}
|
|
70
|
+
if (row.replacedById) {
|
|
71
|
+
// The strongest reuse signal: the legitimate user already rotated this
|
|
72
|
+
// token, but someone (legitimate or attacker) re-presented the old value.
|
|
73
|
+
// Either way, kill the session.
|
|
74
|
+
await this.store.revokeChain(row.id);
|
|
75
|
+
throw new AuthenticationError("Refresh token reuse detected — session revoked");
|
|
76
|
+
}
|
|
77
|
+
if (row.expiresAt.getTime() <= Date.now()) {
|
|
78
|
+
throw new AuthenticationError("Refresh token expired");
|
|
79
|
+
}
|
|
80
|
+
// Mint the successor.
|
|
81
|
+
const newAccess = await this.signer.sign({
|
|
82
|
+
subject: row.accountId,
|
|
83
|
+
ttlSec: this.accessTtlSec,
|
|
84
|
+
});
|
|
85
|
+
const newRefreshRaw = generateRefreshTokenValue();
|
|
86
|
+
const newRefreshHash = hashRefreshToken(newRefreshRaw);
|
|
87
|
+
const newRefreshExpiresAt = new Date((Math.floor(Date.now() / 1000) + this.refreshTtlSec) * 1000);
|
|
88
|
+
const newRow = await this.store.rotate(row.id, {
|
|
89
|
+
accountId: row.accountId,
|
|
90
|
+
tokenHash: newRefreshHash,
|
|
91
|
+
expiresAt: newRefreshExpiresAt,
|
|
92
|
+
userAgent: audit.userAgent,
|
|
93
|
+
issuedFromIp: audit.ip,
|
|
94
|
+
});
|
|
95
|
+
return {
|
|
96
|
+
accessToken: newAccess.token,
|
|
97
|
+
refreshToken: newRefreshRaw,
|
|
98
|
+
accessTokenExpiresAt: newAccess.expiresAt,
|
|
99
|
+
refreshTokenExpiresAt: Math.floor(newRefreshExpiresAt.getTime() / 1000),
|
|
100
|
+
refreshTokenId: newRow.id,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Revoke a single refresh token. Idempotent — already-revoked tokens are
|
|
105
|
+
* a no-op. Used at logout. The call is forgiving by design: an attacker
|
|
106
|
+
* presenting an unknown token shouldn't get a different response from
|
|
107
|
+
* one presenting a valid token.
|
|
108
|
+
*/
|
|
109
|
+
async revoke(presentedRefreshToken) {
|
|
110
|
+
const tokenHash = hashRefreshToken(presentedRefreshToken);
|
|
111
|
+
const row = await this.store.findByHash(tokenHash);
|
|
112
|
+
if (!row)
|
|
113
|
+
return;
|
|
114
|
+
if (row.revokedAt)
|
|
115
|
+
return;
|
|
116
|
+
await this.store.revoke(row.id);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Revoke every active refresh token for an account. Used at password
|
|
120
|
+
* reset, "sign out everywhere", and admin-driven session termination.
|
|
121
|
+
* Returns the number of tokens revoked for log correlation.
|
|
122
|
+
*/
|
|
123
|
+
async revokeAccount(accountId) {
|
|
124
|
+
return this.store.revokeAllForAccount(accountId);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=AuthFlow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthFlow.js","sourceRoot":"","sources":["../../../../src/app/auth/jwt/AuthFlow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
|
|
2
|
+
import type { PgTable } from "drizzle-orm/pg-core";
|
|
3
|
+
import type { IssueRefreshTokenInput, RefreshTokenRecord, RefreshTokenStore } from "./RefreshTokenStore.js";
|
|
4
|
+
/**
|
|
5
|
+
* `DrizzleRefreshTokenStore` — Postgres-backed implementation of the refresh-
|
|
6
|
+
* token rotation contract.
|
|
7
|
+
*
|
|
8
|
+
* Works against any `refresh_tokens`-shaped table (the reference table lives in
|
|
9
|
+
* `modules/accounts/schema.ts`). Pulls the table reference in via the
|
|
10
|
+
* constructor so consumers who customize the schema (extending columns,
|
|
11
|
+
* renaming, multi-tenancy) can pass their own table without forking this class.
|
|
12
|
+
*
|
|
13
|
+
* `revokeChain()` uses a single recursive CTE that walks both directions
|
|
14
|
+
* (ancestors via `replaced_by_id` lookups, descendants via the same column
|
|
15
|
+
* forward) so reuse-detection completes in one round-trip even on long
|
|
16
|
+
* chains. The CTE is marked stable for query planning.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Structural shape of the `refresh_tokens` table the store relies on. Kept
|
|
20
|
+
* narrow on purpose — consumers can extend the table with extra columns and
|
|
21
|
+
* still satisfy this contract.
|
|
22
|
+
*/
|
|
23
|
+
export interface RefreshTokensTable {
|
|
24
|
+
id: unknown;
|
|
25
|
+
accountId: unknown;
|
|
26
|
+
tokenHash: unknown;
|
|
27
|
+
expiresAt: unknown;
|
|
28
|
+
revokedAt: unknown;
|
|
29
|
+
replacedById: unknown;
|
|
30
|
+
userAgent: unknown;
|
|
31
|
+
issuedFromIp: unknown;
|
|
32
|
+
}
|
|
33
|
+
type RefreshTokensPgTable = PgTable & {
|
|
34
|
+
id: {
|
|
35
|
+
name: string;
|
|
36
|
+
};
|
|
37
|
+
accountId: {
|
|
38
|
+
name: string;
|
|
39
|
+
};
|
|
40
|
+
tokenHash: {
|
|
41
|
+
name: string;
|
|
42
|
+
};
|
|
43
|
+
expiresAt: {
|
|
44
|
+
name: string;
|
|
45
|
+
};
|
|
46
|
+
revokedAt: {
|
|
47
|
+
name: string;
|
|
48
|
+
};
|
|
49
|
+
replacedById: {
|
|
50
|
+
name: string;
|
|
51
|
+
};
|
|
52
|
+
userAgent: {
|
|
53
|
+
name: string;
|
|
54
|
+
};
|
|
55
|
+
issuedFromIp: {
|
|
56
|
+
name: string;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
export interface DrizzleRefreshTokenStoreOptions<TSchema extends Record<string, unknown>> {
|
|
60
|
+
db: NodePgDatabase<TSchema>;
|
|
61
|
+
/**
|
|
62
|
+
* Reference to the `refresh_tokens` table — e.g. the one exported from your
|
|
63
|
+
* accounts module (`modules/accounts/schema.ts`). Must satisfy the structural
|
|
64
|
+
* columns above.
|
|
65
|
+
*/
|
|
66
|
+
table: RefreshTokensPgTable;
|
|
67
|
+
}
|
|
68
|
+
export declare class DrizzleRefreshTokenStore<TSchema extends Record<string, unknown>> implements RefreshTokenStore {
|
|
69
|
+
private readonly db;
|
|
70
|
+
private readonly table;
|
|
71
|
+
constructor(opts: DrizzleRefreshTokenStoreOptions<TSchema>);
|
|
72
|
+
issue(input: IssueRefreshTokenInput): Promise<RefreshTokenRecord>;
|
|
73
|
+
findByHash(tokenHash: string): Promise<RefreshTokenRecord | null>;
|
|
74
|
+
rotate(oldId: string, newToken: IssueRefreshTokenInput): Promise<RefreshTokenRecord>;
|
|
75
|
+
revoke(id: string): Promise<void>;
|
|
76
|
+
revokeChain(id: string): Promise<number>;
|
|
77
|
+
revokeAllForAccount(accountId: string): Promise<number>;
|
|
78
|
+
}
|
|
79
|
+
export {};
|
|
80
|
+
//# sourceMappingURL=DrizzleRefreshTokenStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DrizzleRefreshTokenStore.d.ts","sourceRoot":"","sources":["../../../../src/app/auth/jwt/DrizzleRefreshTokenStore.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,KAAK,EACV,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAEhC;;;;;;;;;;;;;GAaG;AAEH;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,KAAK,oBAAoB,GAAG,OAAO,GAAG;IACpC,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACrB,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5B,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5B,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5B,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5B,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/B,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5B,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAChC,CAAC;AAaF,MAAM,WAAW,+BAA+B,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACtF,EAAE,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;IAC5B;;;;OAIG;IACH,KAAK,EAAE,oBAAoB,CAAC;CAC7B;AAED,qBAAa,wBAAwB,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAC3E,YAAW,iBAAiB;IAE5B,OAAO,CAAC,QAAQ,CAAC,EAAE,CAA0B;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuB;gBAEjC,IAAI,EAAE,+BAA+B,CAAC,OAAO,CAAC;IAKpD,KAAK,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAcjE,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAUjE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,sBAAsB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAuBpF,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOjC,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA8BxC,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAiB9D"}
|