@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,70 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* v4 validation surface — Zod schemas piped through `validate('json' | ...)`
|
|
5
|
+
* at the route, with `c.req.valid('json')` reading parsed input. The route
|
|
6
|
+
* registry captures these schemas so MCP tools, the typed-client export, and
|
|
7
|
+
* the eventual OpenAPI compat layer all see the same contract.
|
|
8
|
+
*
|
|
9
|
+
* Field shapes mirror this module's `accounts` table (../schema.ts).
|
|
10
|
+
* Consumers who customize the schema via `createApp({ schema })` should also
|
|
11
|
+
* customize these schemas (extend / override) so server-side validation
|
|
12
|
+
* matches the persisted shape.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const FIREBASE_UID_MAX = 128;
|
|
16
|
+
const EMAIL_MAX = 320;
|
|
17
|
+
const DISPLAY_NAME_MAX = 200;
|
|
18
|
+
|
|
19
|
+
export const createAccountSchema = z
|
|
20
|
+
.object({
|
|
21
|
+
/**
|
|
22
|
+
* Stable subject identifier from the AuthProvider. Optional at create
|
|
23
|
+
* time so service-side flows (e.g., admin-creates-pending-account)
|
|
24
|
+
* can fill it in later when the user first signs in.
|
|
25
|
+
*/
|
|
26
|
+
firebaseUid: z.string().min(1).max(FIREBASE_UID_MAX).optional(),
|
|
27
|
+
email: z.string().email().max(EMAIL_MAX),
|
|
28
|
+
emailVerified: z.boolean().optional(),
|
|
29
|
+
displayName: z.string().min(1).max(DISPLAY_NAME_MAX).optional(),
|
|
30
|
+
isActive: z.boolean().optional(),
|
|
31
|
+
roleId: z.string().uuid().optional(),
|
|
32
|
+
})
|
|
33
|
+
.strict();
|
|
34
|
+
|
|
35
|
+
export const updateAccountSchema = z
|
|
36
|
+
.object({
|
|
37
|
+
firebaseUid: z.string().min(1).max(FIREBASE_UID_MAX).optional(),
|
|
38
|
+
email: z.string().email().max(EMAIL_MAX).optional(),
|
|
39
|
+
emailVerified: z.boolean().optional(),
|
|
40
|
+
displayName: z.string().min(1).max(DISPLAY_NAME_MAX).optional(),
|
|
41
|
+
isActive: z.boolean().optional(),
|
|
42
|
+
/** `null` clears the role assignment (FK is nullable). */
|
|
43
|
+
roleId: z.string().uuid().nullable().optional(),
|
|
44
|
+
})
|
|
45
|
+
.strict();
|
|
46
|
+
|
|
47
|
+
export const accountIdParamSchema = z.object({
|
|
48
|
+
id: z.string().uuid(),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* `?search=foo&page=1&perPage=20&isActive=true&roleId=...`
|
|
53
|
+
*
|
|
54
|
+
* `coerce.number` lets the client send the values as strings (the only
|
|
55
|
+
* shape `c.req.query()` produces) and still get number-typed values out.
|
|
56
|
+
*/
|
|
57
|
+
export const listAccountsQuerySchema = z
|
|
58
|
+
.object({
|
|
59
|
+
search: z.string().min(1).optional(),
|
|
60
|
+
isActive: z.enum(["true", "false"]).optional(),
|
|
61
|
+
roleId: z.string().uuid().optional(),
|
|
62
|
+
page: z.coerce.number().int().positive().default(1),
|
|
63
|
+
perPage: z.coerce.number().int().positive().max(100).default(20),
|
|
64
|
+
})
|
|
65
|
+
.strict();
|
|
66
|
+
|
|
67
|
+
export type CreateAccountInput = z.infer<typeof createAccountSchema>;
|
|
68
|
+
export type UpdateAccountInput = z.infer<typeof updateAccountSchema>;
|
|
69
|
+
export type ListAccountsQuery = z.infer<typeof listAccountsQuerySchema>;
|
|
70
|
+
export type AccountIdParam = z.infer<typeof accountIdParamSchema>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { GoogleOAuthAdapter, type GoogleOAuthAdapterOptions } from "./GoogleOAuthAdapter.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Gmail-flavored Google OAuth adapter — convenience subclass that
|
|
5
|
+
* pre-fills `providerCode: "gmail"`.
|
|
6
|
+
*
|
|
7
|
+
* Same OAuth 2.0 flow as `GoogleOAuthAdapter` (Gmail uses the same
|
|
8
|
+
* Google Identity endpoints; Gmail-specific scopes like
|
|
9
|
+
* `https://www.googleapis.com/auth/gmail.readonly` are caller-
|
|
10
|
+
* supplied via `AuthUrlOptions.scopes`, not adapter-specific).
|
|
11
|
+
*
|
|
12
|
+
* Why a separate class instead of a runtime tag: connection rows
|
|
13
|
+
* carry `providerCode` as the cross-table key, and consumers
|
|
14
|
+
* frequently want Gmail-scoped connections to live alongside
|
|
15
|
+
* generic Google sign-in connections without colliding on the
|
|
16
|
+
* unique (account_id, provider_code) composite. Registering both
|
|
17
|
+
* `GoogleOAuthAdapter` (`"google"`) and `GmailOAuthAdapter`
|
|
18
|
+
* (`"gmail"`) in the same registry gives consumers two distinct
|
|
19
|
+
* provider rows per account.
|
|
20
|
+
*
|
|
21
|
+
* Usage:
|
|
22
|
+
*
|
|
23
|
+
* const adapters = oauthAdapterRegistry(
|
|
24
|
+
* new GoogleOAuthAdapter(),
|
|
25
|
+
* new GmailOAuthAdapter(),
|
|
26
|
+
* );
|
|
27
|
+
*
|
|
28
|
+
* All other options forward to the underlying `GoogleOAuthAdapter`
|
|
29
|
+
* (defaultAccessType, defaultPrompt, fetchImpl, …).
|
|
30
|
+
*/
|
|
31
|
+
export class GmailOAuthAdapter extends GoogleOAuthAdapter {
|
|
32
|
+
constructor(opts: Omit<GoogleOAuthAdapterOptions, "providerCode"> = {}) {
|
|
33
|
+
super({ ...opts, providerCode: "gmail" });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AuthUrlOptions,
|
|
3
|
+
ExchangeCodeOptions,
|
|
4
|
+
OAuthAdapter,
|
|
5
|
+
OAuthClientCredentials,
|
|
6
|
+
TokenResponse,
|
|
7
|
+
} from "./OAuthAdapter.js";
|
|
8
|
+
import {
|
|
9
|
+
InvalidCredentialsError,
|
|
10
|
+
OAuthRateLimitError,
|
|
11
|
+
TokenExchangeError,
|
|
12
|
+
TokenRefreshError,
|
|
13
|
+
} from "./OAuthAdapter.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Google OAuth 2.0 adapter — fetch-based, no SDK dependency.
|
|
17
|
+
*
|
|
18
|
+
* Implements the framework's `OAuthAdapter` interface against
|
|
19
|
+
* Google's OAuth 2.0 endpoints directly:
|
|
20
|
+
* - Authorization: https://accounts.google.com/o/oauth2/v2/auth
|
|
21
|
+
* - Token exchange: https://oauth2.googleapis.com/token
|
|
22
|
+
* - User info: https://openidconnect.googleapis.com/v1/userinfo
|
|
23
|
+
* - Revoke: https://oauth2.googleapis.com/revoke
|
|
24
|
+
*
|
|
25
|
+
* Replaces v3's `googleapis`-SDK-backed adapter. Fetch-based means
|
|
26
|
+
* the adapter works in every runtime (Node, Workers, Bun) without
|
|
27
|
+
* a 5+ MB SDK in the bundle. Consumers who want the full Google
|
|
28
|
+
* SDK ergonomics for non-OAuth API calls (Gmail / Drive / Calendar
|
|
29
|
+
* etc.) install `googleapis` separately.
|
|
30
|
+
*
|
|
31
|
+
* Provider-specific defaults the framework's contract doesn't
|
|
32
|
+
* model:
|
|
33
|
+
* - `access_type: "offline"` — required to receive a refresh
|
|
34
|
+
* token. Set via `providerOptions` if you want the v3 default
|
|
35
|
+
* behavior.
|
|
36
|
+
* - `prompt: "consent"` — forces re-consent so a fresh refresh
|
|
37
|
+
* token is reissued even when the user has already granted
|
|
38
|
+
* access. Useful for "reconnect" flows.
|
|
39
|
+
* - `include_granted_scopes: true` — incremental authorization
|
|
40
|
+
* across multiple Google scopes.
|
|
41
|
+
*
|
|
42
|
+
* Default authorize URL adds `access_type=offline&prompt=consent`
|
|
43
|
+
* automatically — that's the v3 behavior and the most common
|
|
44
|
+
* Google flow. Override via `opts.providerOptions` per-call:
|
|
45
|
+
* ```ts
|
|
46
|
+
* adapter.buildAuthorizationUrl(creds, {
|
|
47
|
+
* state, scopes,
|
|
48
|
+
* providerOptions: { prompt: "select_account" },
|
|
49
|
+
* });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
const AUTHORIZE_ENDPOINT = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
54
|
+
const TOKEN_ENDPOINT = "https://oauth2.googleapis.com/token";
|
|
55
|
+
const USERINFO_ENDPOINT = "https://openidconnect.googleapis.com/v1/userinfo";
|
|
56
|
+
const REVOKE_ENDPOINT = "https://oauth2.googleapis.com/revoke";
|
|
57
|
+
|
|
58
|
+
export interface GoogleOAuthAdapterOptions {
|
|
59
|
+
/** Stable provider identifier. Default `"google"`. */
|
|
60
|
+
providerCode?: string;
|
|
61
|
+
/** Override `fetch` (tests). */
|
|
62
|
+
fetchImpl?: typeof fetch;
|
|
63
|
+
/** Default `access_type`. Default `"offline"` (returns a refresh token). */
|
|
64
|
+
defaultAccessType?: "online" | "offline";
|
|
65
|
+
/** Default `prompt`. Default `"consent"` (forces fresh refresh token). */
|
|
66
|
+
defaultPrompt?: "none" | "consent" | "select_account";
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export class GoogleOAuthAdapter implements OAuthAdapter {
|
|
70
|
+
readonly providerCode: string;
|
|
71
|
+
private readonly fetchImpl: typeof fetch;
|
|
72
|
+
private readonly defaultAccessType: "online" | "offline";
|
|
73
|
+
private readonly defaultPrompt: "none" | "consent" | "select_account";
|
|
74
|
+
|
|
75
|
+
constructor(opts: GoogleOAuthAdapterOptions = {}) {
|
|
76
|
+
this.providerCode = opts.providerCode ?? "google";
|
|
77
|
+
this.fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
78
|
+
this.defaultAccessType = opts.defaultAccessType ?? "offline";
|
|
79
|
+
this.defaultPrompt = opts.defaultPrompt ?? "consent";
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
buildAuthorizationUrl(credentials: OAuthClientCredentials, opts: AuthUrlOptions): string {
|
|
83
|
+
const params = new URLSearchParams({
|
|
84
|
+
client_id: credentials.clientId,
|
|
85
|
+
redirect_uri: credentials.redirectUri,
|
|
86
|
+
response_type: "code",
|
|
87
|
+
scope: opts.scopes.join(" "),
|
|
88
|
+
state: opts.state,
|
|
89
|
+
access_type: this.defaultAccessType,
|
|
90
|
+
prompt: this.defaultPrompt,
|
|
91
|
+
include_granted_scopes: "true",
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// PKCE: emit challenge params when supplied. Adapters that don't
|
|
95
|
+
// receive a challenge (consumers running against the old contract)
|
|
96
|
+
// still produce a valid URL — the params are simply omitted.
|
|
97
|
+
if (opts.codeChallenge) {
|
|
98
|
+
params.set("code_challenge", opts.codeChallenge);
|
|
99
|
+
params.set("code_challenge_method", opts.codeChallengeMethod ?? "S256");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Provider-specific overrides win.
|
|
103
|
+
if (opts.providerOptions) {
|
|
104
|
+
for (const [key, val] of Object.entries(opts.providerOptions)) {
|
|
105
|
+
params.set(key, String(val));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return `${AUTHORIZE_ENDPOINT}?${params.toString()}`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async exchangeCodeForTokens(
|
|
113
|
+
code: string,
|
|
114
|
+
credentials: OAuthClientCredentials,
|
|
115
|
+
opts: ExchangeCodeOptions = {},
|
|
116
|
+
): Promise<TokenResponse> {
|
|
117
|
+
const formBody = new URLSearchParams({
|
|
118
|
+
code,
|
|
119
|
+
client_id: credentials.clientId,
|
|
120
|
+
client_secret: credentials.clientSecret,
|
|
121
|
+
redirect_uri: credentials.redirectUri,
|
|
122
|
+
grant_type: "authorization_code",
|
|
123
|
+
});
|
|
124
|
+
if (opts.codeVerifier) formBody.set("code_verifier", opts.codeVerifier);
|
|
125
|
+
|
|
126
|
+
const response = await this.fetchImpl(TOKEN_ENDPOINT, {
|
|
127
|
+
method: "POST",
|
|
128
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
129
|
+
body: formBody.toString(),
|
|
130
|
+
signal: opts.signal,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
if (!response.ok) {
|
|
134
|
+
throw this.translateError(response, "exchange");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const body = (await response.json()) as GoogleTokenResponse;
|
|
138
|
+
return tokenResponseFromGoogle(body);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async refreshTokens(
|
|
142
|
+
refreshToken: string,
|
|
143
|
+
credentials: OAuthClientCredentials,
|
|
144
|
+
opts: { signal?: AbortSignal } = {},
|
|
145
|
+
): Promise<TokenResponse> {
|
|
146
|
+
const response = await this.fetchImpl(TOKEN_ENDPOINT, {
|
|
147
|
+
method: "POST",
|
|
148
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
149
|
+
body: new URLSearchParams({
|
|
150
|
+
refresh_token: refreshToken,
|
|
151
|
+
client_id: credentials.clientId,
|
|
152
|
+
client_secret: credentials.clientSecret,
|
|
153
|
+
grant_type: "refresh_token",
|
|
154
|
+
}).toString(),
|
|
155
|
+
signal: opts.signal,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
if (!response.ok) {
|
|
159
|
+
throw this.translateError(response, "refresh");
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const body = (await response.json()) as GoogleTokenResponse;
|
|
163
|
+
// Refresh responses don't always include a fresh refresh_token —
|
|
164
|
+
// when omitted, Google expects callers to keep using the
|
|
165
|
+
// existing one. Pass through what they sent (typically just
|
|
166
|
+
// the new access_token + expires_in).
|
|
167
|
+
return {
|
|
168
|
+
...tokenResponseFromGoogle(body),
|
|
169
|
+
// Preserve the original refresh token when Google doesn't
|
|
170
|
+
// rotate (most refresh responses don't).
|
|
171
|
+
refreshToken: body.refresh_token ?? refreshToken,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async getProviderAccountId(
|
|
176
|
+
tokens: TokenResponse,
|
|
177
|
+
_credentials: OAuthClientCredentials,
|
|
178
|
+
opts: { signal?: AbortSignal } = {},
|
|
179
|
+
): Promise<string> {
|
|
180
|
+
void _credentials;
|
|
181
|
+
if (!tokens.accessToken) {
|
|
182
|
+
throw new TokenExchangeError(
|
|
183
|
+
this.providerCode,
|
|
184
|
+
"cannot resolve provider account id without an access token",
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
const response = await this.fetchImpl(USERINFO_ENDPOINT, {
|
|
188
|
+
headers: { authorization: `Bearer ${tokens.accessToken}` },
|
|
189
|
+
signal: opts.signal,
|
|
190
|
+
});
|
|
191
|
+
if (!response.ok) {
|
|
192
|
+
throw this.translateError(response, "userinfo");
|
|
193
|
+
}
|
|
194
|
+
const body = (await response.json()) as GoogleUserInfo;
|
|
195
|
+
if (!body.sub) {
|
|
196
|
+
throw new TokenExchangeError(this.providerCode, "userinfo response missing `sub` claim");
|
|
197
|
+
}
|
|
198
|
+
return body.sub;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async revokeAccess(
|
|
202
|
+
accessToken: string,
|
|
203
|
+
_credentials: OAuthClientCredentials,
|
|
204
|
+
opts: { signal?: AbortSignal } = {},
|
|
205
|
+
): Promise<void> {
|
|
206
|
+
void _credentials;
|
|
207
|
+
// Google's revoke endpoint accepts the token via querystring.
|
|
208
|
+
// Failures are best-effort; the routes layer doesn't abort the
|
|
209
|
+
// local clear when revoke throws (per OAuthAdapter contract).
|
|
210
|
+
await this.fetchImpl(`${REVOKE_ENDPOINT}?token=${encodeURIComponent(accessToken)}`, {
|
|
211
|
+
method: "POST",
|
|
212
|
+
signal: opts.signal,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
private translateError(
|
|
217
|
+
response: Response,
|
|
218
|
+
operation: "exchange" | "refresh" | "userinfo",
|
|
219
|
+
): Error {
|
|
220
|
+
if (response.status === 401) {
|
|
221
|
+
return new InvalidCredentialsError(
|
|
222
|
+
this.providerCode,
|
|
223
|
+
`Google ${operation}: invalid credentials (401)`,
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
if (response.status === 429) {
|
|
227
|
+
const retryAfter = response.headers.get("retry-after");
|
|
228
|
+
return new OAuthRateLimitError(
|
|
229
|
+
this.providerCode,
|
|
230
|
+
`Google ${operation}: rate limit (429)`,
|
|
231
|
+
retryAfter ? Number.parseInt(retryAfter, 10) : undefined,
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
if (operation === "exchange") {
|
|
235
|
+
return new TokenExchangeError(
|
|
236
|
+
this.providerCode,
|
|
237
|
+
`Google ${operation}: ${response.status} ${response.statusText}`,
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
return new TokenRefreshError(
|
|
241
|
+
this.providerCode,
|
|
242
|
+
`Google ${operation}: ${response.status} ${response.statusText}`,
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// ─── Internal types ────────────────────────────────────────────────────
|
|
248
|
+
|
|
249
|
+
interface GoogleTokenResponse {
|
|
250
|
+
access_token: string;
|
|
251
|
+
refresh_token?: string;
|
|
252
|
+
expires_in?: number;
|
|
253
|
+
scope?: string;
|
|
254
|
+
token_type?: string;
|
|
255
|
+
id_token?: string;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
interface GoogleUserInfo {
|
|
259
|
+
sub: string;
|
|
260
|
+
email?: string;
|
|
261
|
+
email_verified?: boolean;
|
|
262
|
+
name?: string;
|
|
263
|
+
picture?: string;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function tokenResponseFromGoogle(body: GoogleTokenResponse): TokenResponse {
|
|
267
|
+
return {
|
|
268
|
+
accessToken: body.access_token,
|
|
269
|
+
refreshToken: body.refresh_token,
|
|
270
|
+
expiresAt:
|
|
271
|
+
body.expires_in !== undefined ? new Date(Date.now() + body.expires_in * 1000) : undefined,
|
|
272
|
+
scope: body.scope,
|
|
273
|
+
tokenType: body.token_type,
|
|
274
|
+
metadata: {
|
|
275
|
+
...(body.id_token ? { id_token: body.id_token } : {}),
|
|
276
|
+
},
|
|
277
|
+
};
|
|
278
|
+
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AuthUrlOptions,
|
|
3
|
+
ExchangeCodeOptions,
|
|
4
|
+
OAuthAdapter,
|
|
5
|
+
OAuthClientCredentials,
|
|
6
|
+
TokenResponse,
|
|
7
|
+
} from "./OAuthAdapter.js";
|
|
8
|
+
import {
|
|
9
|
+
InvalidCredentialsError,
|
|
10
|
+
OAuthRateLimitError,
|
|
11
|
+
TokenExchangeError,
|
|
12
|
+
TokenRefreshError,
|
|
13
|
+
} from "./OAuthAdapter.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Microsoft / Azure AD OAuth 2.0 adapter — fetch-based, no SDK.
|
|
17
|
+
*
|
|
18
|
+
* Implements the framework's `OAuthAdapter` interface against
|
|
19
|
+
* Microsoft's v2.0 endpoints directly:
|
|
20
|
+
* - Authorization: https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize
|
|
21
|
+
* - Token exchange: https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
|
|
22
|
+
* - User info: https://graph.microsoft.com/v1.0/me
|
|
23
|
+
* - Revoke: standard OAuth 2.0 has no Microsoft revoke endpoint.
|
|
24
|
+
* `revokeAccess` is a best-effort no-op (returns silently); the
|
|
25
|
+
* routes layer's local clear runs unconditionally per the
|
|
26
|
+
* `OAuthAdapter` contract.
|
|
27
|
+
*
|
|
28
|
+
* Tenant handling: defaults to `"common"` (multi-tenant apps —
|
|
29
|
+
* accepts personal MS accounts + work accounts). Override via
|
|
30
|
+
* `tenant` in the constructor for single-tenant deployments
|
|
31
|
+
* (`new MicrosoftOAuthAdapter({ tenant: "contoso.onmicrosoft.com" })`)
|
|
32
|
+
* or per-call via `opts.providerOptions.tenant` on `buildAuthorizationUrl`.
|
|
33
|
+
*
|
|
34
|
+
* Microsoft's `provider_account_id` resolves from the Graph `/me`
|
|
35
|
+
* endpoint's `id` field — a stable directory object identifier
|
|
36
|
+
* suitable for cross-session linkage. The `oid` claim from the
|
|
37
|
+
* id_token is equivalent for token-only resolution paths.
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
const AUTHORIZE_PATH = "/oauth2/v2.0/authorize";
|
|
41
|
+
const TOKEN_PATH = "/oauth2/v2.0/token";
|
|
42
|
+
const ME_ENDPOINT = "https://graph.microsoft.com/v1.0/me";
|
|
43
|
+
|
|
44
|
+
export interface MicrosoftOAuthAdapterOptions {
|
|
45
|
+
/** Stable provider identifier. Default `"microsoft"`. */
|
|
46
|
+
providerCode?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Microsoft tenant. Default `"common"` (multi-tenant). Use
|
|
49
|
+
* `"organizations"` to restrict to work/school accounts,
|
|
50
|
+
* `"consumers"` for personal MS accounts only, or a tenant ID /
|
|
51
|
+
* domain for a single-tenant app.
|
|
52
|
+
*/
|
|
53
|
+
tenant?: string;
|
|
54
|
+
/** Override `fetch` (tests). */
|
|
55
|
+
fetchImpl?: typeof fetch;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export class MicrosoftOAuthAdapter implements OAuthAdapter {
|
|
59
|
+
readonly providerCode: string;
|
|
60
|
+
private readonly tenant: string;
|
|
61
|
+
private readonly fetchImpl: typeof fetch;
|
|
62
|
+
|
|
63
|
+
constructor(opts: MicrosoftOAuthAdapterOptions = {}) {
|
|
64
|
+
this.providerCode = opts.providerCode ?? "microsoft";
|
|
65
|
+
this.tenant = opts.tenant ?? "common";
|
|
66
|
+
this.fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
buildAuthorizationUrl(credentials: OAuthClientCredentials, opts: AuthUrlOptions): string {
|
|
70
|
+
const tenant = this.resolveTenant(opts.providerOptions);
|
|
71
|
+
const params = new URLSearchParams({
|
|
72
|
+
client_id: credentials.clientId,
|
|
73
|
+
redirect_uri: credentials.redirectUri,
|
|
74
|
+
response_type: "code",
|
|
75
|
+
scope: opts.scopes.join(" "),
|
|
76
|
+
state: opts.state,
|
|
77
|
+
response_mode: "query",
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// PKCE: emit challenge params when supplied (F12).
|
|
81
|
+
if (opts.codeChallenge) {
|
|
82
|
+
params.set("code_challenge", opts.codeChallenge);
|
|
83
|
+
params.set("code_challenge_method", opts.codeChallengeMethod ?? "S256");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Pass-through provider options excluding `tenant` (consumed above).
|
|
87
|
+
if (opts.providerOptions) {
|
|
88
|
+
for (const [key, val] of Object.entries(opts.providerOptions)) {
|
|
89
|
+
if (key === "tenant") continue;
|
|
90
|
+
params.set(key, String(val));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return `https://login.microsoftonline.com/${encodeURIComponent(tenant)}${AUTHORIZE_PATH}?${params.toString()}`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async exchangeCodeForTokens(
|
|
98
|
+
code: string,
|
|
99
|
+
credentials: OAuthClientCredentials,
|
|
100
|
+
opts: ExchangeCodeOptions = {},
|
|
101
|
+
): Promise<TokenResponse> {
|
|
102
|
+
const url = this.tokenUrl();
|
|
103
|
+
const formBody = new URLSearchParams({
|
|
104
|
+
code,
|
|
105
|
+
client_id: credentials.clientId,
|
|
106
|
+
client_secret: credentials.clientSecret,
|
|
107
|
+
redirect_uri: credentials.redirectUri,
|
|
108
|
+
grant_type: "authorization_code",
|
|
109
|
+
});
|
|
110
|
+
if (opts.codeVerifier) formBody.set("code_verifier", opts.codeVerifier);
|
|
111
|
+
|
|
112
|
+
const response = await this.fetchImpl(url, {
|
|
113
|
+
method: "POST",
|
|
114
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
115
|
+
body: formBody.toString(),
|
|
116
|
+
signal: opts.signal,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
if (!response.ok) {
|
|
120
|
+
throw this.translateError(response, "exchange");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const body = (await response.json()) as MicrosoftTokenResponse;
|
|
124
|
+
return tokenResponseFromMicrosoft(body);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async refreshTokens(
|
|
128
|
+
refreshToken: string,
|
|
129
|
+
credentials: OAuthClientCredentials,
|
|
130
|
+
opts: { signal?: AbortSignal } = {},
|
|
131
|
+
): Promise<TokenResponse> {
|
|
132
|
+
const url = this.tokenUrl();
|
|
133
|
+
const response = await this.fetchImpl(url, {
|
|
134
|
+
method: "POST",
|
|
135
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
136
|
+
body: new URLSearchParams({
|
|
137
|
+
refresh_token: refreshToken,
|
|
138
|
+
client_id: credentials.clientId,
|
|
139
|
+
client_secret: credentials.clientSecret,
|
|
140
|
+
grant_type: "refresh_token",
|
|
141
|
+
}).toString(),
|
|
142
|
+
signal: opts.signal,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
if (!response.ok) {
|
|
146
|
+
throw this.translateError(response, "refresh");
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const body = (await response.json()) as MicrosoftTokenResponse;
|
|
150
|
+
// Microsoft typically rotates refresh tokens on refresh; pass
|
|
151
|
+
// through what they send. Fall back to the original on the
|
|
152
|
+
// off-chance Microsoft omits it (consistent with Google's
|
|
153
|
+
// behavior for the same edge case).
|
|
154
|
+
return {
|
|
155
|
+
...tokenResponseFromMicrosoft(body),
|
|
156
|
+
refreshToken: body.refresh_token ?? refreshToken,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async getProviderAccountId(
|
|
161
|
+
tokens: TokenResponse,
|
|
162
|
+
_credentials: OAuthClientCredentials,
|
|
163
|
+
opts: { signal?: AbortSignal } = {},
|
|
164
|
+
): Promise<string> {
|
|
165
|
+
void _credentials;
|
|
166
|
+
if (!tokens.accessToken) {
|
|
167
|
+
throw new TokenExchangeError(
|
|
168
|
+
this.providerCode,
|
|
169
|
+
"cannot resolve provider account id without an access token",
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
const response = await this.fetchImpl(ME_ENDPOINT, {
|
|
173
|
+
headers: { authorization: `Bearer ${tokens.accessToken}` },
|
|
174
|
+
signal: opts.signal,
|
|
175
|
+
});
|
|
176
|
+
if (!response.ok) {
|
|
177
|
+
throw this.translateError(response, "userinfo");
|
|
178
|
+
}
|
|
179
|
+
const body = (await response.json()) as MicrosoftMeResponse;
|
|
180
|
+
if (!body.id) {
|
|
181
|
+
throw new TokenExchangeError(this.providerCode, "Graph /me response missing `id` field");
|
|
182
|
+
}
|
|
183
|
+
return body.id;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Microsoft has no token-revoke endpoint in OAuth 2.0. Best-effort
|
|
187
|
+
// no-op per the OAuthAdapter contract; the routes layer's local
|
|
188
|
+
// clear runs regardless.
|
|
189
|
+
async revokeAccess(): Promise<void> {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ─── Internals ──────────────────────────────────────────────────────
|
|
194
|
+
|
|
195
|
+
private resolveTenant(providerOptions: AuthUrlOptions["providerOptions"]): string {
|
|
196
|
+
const override = providerOptions?.tenant;
|
|
197
|
+
if (typeof override === "string" && override.length > 0) return override;
|
|
198
|
+
return this.tenant;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
private tokenUrl(tenantOverride?: string): string {
|
|
202
|
+
const tenant = tenantOverride ?? this.tenant;
|
|
203
|
+
return `https://login.microsoftonline.com/${encodeURIComponent(tenant)}${TOKEN_PATH}`;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
private translateError(
|
|
207
|
+
response: Response,
|
|
208
|
+
operation: "exchange" | "refresh" | "userinfo",
|
|
209
|
+
): Error {
|
|
210
|
+
if (response.status === 401) {
|
|
211
|
+
return new InvalidCredentialsError(
|
|
212
|
+
this.providerCode,
|
|
213
|
+
`Microsoft ${operation}: invalid credentials (401)`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
if (response.status === 429) {
|
|
217
|
+
const retryAfter = response.headers.get("retry-after");
|
|
218
|
+
return new OAuthRateLimitError(
|
|
219
|
+
this.providerCode,
|
|
220
|
+
`Microsoft ${operation}: rate limit (429)`,
|
|
221
|
+
retryAfter ? Number.parseInt(retryAfter, 10) : undefined,
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
if (operation === "exchange") {
|
|
225
|
+
return new TokenExchangeError(
|
|
226
|
+
this.providerCode,
|
|
227
|
+
`Microsoft ${operation}: ${response.status} ${response.statusText}`,
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
return new TokenRefreshError(
|
|
231
|
+
this.providerCode,
|
|
232
|
+
`Microsoft ${operation}: ${response.status} ${response.statusText}`,
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ─── Internal types ────────────────────────────────────────────────────
|
|
238
|
+
|
|
239
|
+
interface MicrosoftTokenResponse {
|
|
240
|
+
token_type?: string;
|
|
241
|
+
scope?: string;
|
|
242
|
+
expires_in?: number;
|
|
243
|
+
ext_expires_in?: number;
|
|
244
|
+
access_token: string;
|
|
245
|
+
refresh_token?: string;
|
|
246
|
+
id_token?: string;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
interface MicrosoftMeResponse {
|
|
250
|
+
id?: string;
|
|
251
|
+
userPrincipalName?: string;
|
|
252
|
+
mail?: string;
|
|
253
|
+
displayName?: string;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function tokenResponseFromMicrosoft(body: MicrosoftTokenResponse): TokenResponse {
|
|
257
|
+
return {
|
|
258
|
+
accessToken: body.access_token,
|
|
259
|
+
refreshToken: body.refresh_token,
|
|
260
|
+
expiresAt:
|
|
261
|
+
body.expires_in !== undefined ? new Date(Date.now() + body.expires_in * 1000) : undefined,
|
|
262
|
+
scope: body.scope,
|
|
263
|
+
tokenType: body.token_type,
|
|
264
|
+
metadata: {
|
|
265
|
+
...(body.id_token ? { id_token: body.id_token } : {}),
|
|
266
|
+
...(body.ext_expires_in !== undefined ? { ext_expires_in: body.ext_expires_in } : {}),
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
}
|