@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,777 @@
|
|
|
1
|
+
# `libraries/email/` — Resend-backed transactional email
|
|
2
|
+
|
|
3
|
+
A type-safe email service built around [Resend](https://resend.com/), with a built-in template system (variable substitution, conditionals, loops), batch sending, scheduling, and tagging.
|
|
4
|
+
|
|
5
|
+
> **Install via**: `ship-api add -l email`. Pulls in the `resend` SDK; configure `RESEND_API_KEY` + `RESEND_DEFAULT_FROM` in your `.env`.
|
|
6
|
+
|
|
7
|
+
## What's exported
|
|
8
|
+
|
|
9
|
+
- `EmailService` — the main service class
|
|
10
|
+
- `TemplateRegistry` — manages registered templates
|
|
11
|
+
- `TemplateRenderer` — renders a template with variables
|
|
12
|
+
- The full type set for `SendEmailOptions`, `EmailTemplate<TVars>`, batch payloads, etc.
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import {
|
|
16
|
+
EmailService,
|
|
17
|
+
TemplateRegistry,
|
|
18
|
+
TemplateRenderer,
|
|
19
|
+
type EmailTemplate,
|
|
20
|
+
type SendEmailOptions,
|
|
21
|
+
} from "@sixthsummit/ship-api/libraries/email";
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
## Configuration
|
|
27
|
+
|
|
28
|
+
### Environment Variables
|
|
29
|
+
|
|
30
|
+
Add the following environment variables to your `.env` file:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Required: Resend API key
|
|
34
|
+
RESEND_API_KEY=re_your_api_key_here
|
|
35
|
+
|
|
36
|
+
# Optional: Default "from" email address
|
|
37
|
+
RESEND_DEFAULT_FROM=noreply@yourdomain.com
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Domain Setup
|
|
41
|
+
|
|
42
|
+
Before sending emails, you need to:
|
|
43
|
+
|
|
44
|
+
1. Add and verify your domain in the [Resend dashboard](https://resend.com/domains)
|
|
45
|
+
2. Configure DNS records (SPF, DKIM, DMARC)
|
|
46
|
+
3. Use an email address from your verified domain as the sender
|
|
47
|
+
|
|
48
|
+
## Quick Start
|
|
49
|
+
|
|
50
|
+
Construct the service once in your app's composition root (`src/index.ts`) and inject it into the modules and jobs that send mail:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
// src/index.ts
|
|
54
|
+
import { EmailService } from "@sixthsummit/ship-api/libraries/email";
|
|
55
|
+
import { welcomeTemplate, passwordResetTemplate } from "./templates/index.js";
|
|
56
|
+
import { env } from "./environment.js";
|
|
57
|
+
|
|
58
|
+
const emailService = new EmailService(env.RESEND_API_KEY, env.RESEND_DEFAULT_FROM);
|
|
59
|
+
emailService.registerTemplates([welcomeTemplate, passwordResetTemplate]);
|
|
60
|
+
|
|
61
|
+
// Pass `emailService` into modules / jobs / route deps that need it.
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Sending via a registered template
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
await emailService.sendEmailWithTemplate({
|
|
68
|
+
templateId: "welcome",
|
|
69
|
+
to: "user@example.com",
|
|
70
|
+
variables: {
|
|
71
|
+
firstName: "John",
|
|
72
|
+
lastName: "Doe",
|
|
73
|
+
email: "john@example.com",
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Direct send (no template)
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
await emailService.sendEmail({
|
|
82
|
+
from: "noreply@yourdomain.com",
|
|
83
|
+
to: "user@example.com",
|
|
84
|
+
subject: "Welcome!",
|
|
85
|
+
text: "Welcome to our platform",
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### HTML Email
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
await emailService.sendEmail({
|
|
93
|
+
from: "noreply@yourdomain.com",
|
|
94
|
+
to: "user@example.com",
|
|
95
|
+
subject: "Welcome!",
|
|
96
|
+
html: `
|
|
97
|
+
<h1>Welcome to our platform!</h1>
|
|
98
|
+
<p>We're excited to have you on board.</p>
|
|
99
|
+
`,
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Multiple Recipients
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
await emailService.sendEmail({
|
|
107
|
+
from: "noreply@yourdomain.com",
|
|
108
|
+
to: ["user1@example.com", "user2@example.com"],
|
|
109
|
+
subject: "Team Update",
|
|
110
|
+
html: "<p>Important team announcement</p>",
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Named Recipients
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
await emailService.sendEmail({
|
|
118
|
+
from: { name: "ShipAPI App", email: "noreply@yourdomain.com" },
|
|
119
|
+
to: [
|
|
120
|
+
{ name: "John Doe", email: "john@example.com" },
|
|
121
|
+
{ name: "Jane Smith", email: "jane@example.com" },
|
|
122
|
+
],
|
|
123
|
+
subject: "Welcome Team!",
|
|
124
|
+
html: "<p>Welcome to the team!</p>",
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### CC and BCC
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
await emailService.sendEmail({
|
|
132
|
+
from: "noreply@yourdomain.com",
|
|
133
|
+
to: "user@example.com",
|
|
134
|
+
cc: "manager@example.com",
|
|
135
|
+
bcc: ["audit@example.com", "compliance@example.com"],
|
|
136
|
+
subject: "Project Update",
|
|
137
|
+
html: "<p>Project status update</p>",
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Reply-To
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
await emailService.sendEmail({
|
|
145
|
+
from: "noreply@yourdomain.com",
|
|
146
|
+
to: "user@example.com",
|
|
147
|
+
replyTo: "support@yourdomain.com",
|
|
148
|
+
subject: "Need Help?",
|
|
149
|
+
html: "<p>Click reply if you need assistance</p>",
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Attachments
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
await emailService.sendEmail({
|
|
157
|
+
from: "noreply@yourdomain.com",
|
|
158
|
+
to: "user@example.com",
|
|
159
|
+
subject: "Invoice Attached",
|
|
160
|
+
html: "<p>Please find your invoice attached.</p>",
|
|
161
|
+
attachments: [
|
|
162
|
+
{
|
|
163
|
+
filename: "invoice.pdf",
|
|
164
|
+
content: pdfBuffer, // Buffer
|
|
165
|
+
contentType: "application/pdf",
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
filename: "logo.png",
|
|
169
|
+
content: "base64EncodedString", // Base64 string
|
|
170
|
+
contentType: "image/png",
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
});
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Tags for Tracking
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
await emailService.sendEmail({
|
|
180
|
+
from: "noreply@yourdomain.com",
|
|
181
|
+
to: "user@example.com",
|
|
182
|
+
subject: "Welcome!",
|
|
183
|
+
html: "<p>Welcome email</p>",
|
|
184
|
+
tags: [
|
|
185
|
+
{ name: "category", value: "onboarding" },
|
|
186
|
+
{ name: "user_id", value: "12345" },
|
|
187
|
+
],
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Custom Headers
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
await emailService.sendEmail({
|
|
195
|
+
from: "noreply@yourdomain.com",
|
|
196
|
+
to: "user@example.com",
|
|
197
|
+
subject: "Custom Headers",
|
|
198
|
+
html: "<p>Email with custom headers</p>",
|
|
199
|
+
headers: {
|
|
200
|
+
"X-Custom-Header": "custom-value",
|
|
201
|
+
"X-Priority": "1",
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Scheduled Emails
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
await emailService.sendEmail({
|
|
210
|
+
from: "noreply@yourdomain.com",
|
|
211
|
+
to: "user@example.com",
|
|
212
|
+
subject: "Scheduled Email",
|
|
213
|
+
html: "<p>This email was scheduled</p>",
|
|
214
|
+
scheduledAt: "2025-12-31T23:59:59Z", // ISO 8601 format
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Batch Emails
|
|
219
|
+
|
|
220
|
+
Send up to 100 emails in a single batch for better performance:
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
const results = await emailService.sendBatchEmails({
|
|
224
|
+
emails: [
|
|
225
|
+
{
|
|
226
|
+
from: "noreply@yourdomain.com",
|
|
227
|
+
to: "user1@example.com",
|
|
228
|
+
subject: "Welcome User 1",
|
|
229
|
+
html: "<p>Personalized welcome message</p>",
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
from: "noreply@yourdomain.com",
|
|
233
|
+
to: "user2@example.com",
|
|
234
|
+
subject: "Welcome User 2",
|
|
235
|
+
html: "<p>Personalized welcome message</p>",
|
|
236
|
+
},
|
|
237
|
+
// ... up to 100 emails
|
|
238
|
+
],
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Check results
|
|
242
|
+
results.data?.forEach((result, index) => {
|
|
243
|
+
console.log(`Email ${index} sent with ID: ${result.id}`);
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Using Default From Address
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
// Set default from address in constructor
|
|
251
|
+
const emailService = new EmailService(undefined, "noreply@yourdomain.com");
|
|
252
|
+
|
|
253
|
+
// Now you can omit "from" in sendEmail
|
|
254
|
+
await emailService.sendEmail({
|
|
255
|
+
to: "user@example.com",
|
|
256
|
+
subject: "Welcome!",
|
|
257
|
+
text: "Welcome to our platform",
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// Or set it later
|
|
261
|
+
emailService.setDefaultFrom("support@yourdomain.com");
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Email Templates
|
|
265
|
+
|
|
266
|
+
The email service includes a powerful template system that allows you to create reusable email templates with variable substitution, conditionals, and loops.
|
|
267
|
+
|
|
268
|
+
### Using Templates
|
|
269
|
+
|
|
270
|
+
Register templates once at app startup (in `src/index.ts`), then use the configured `emailService` instance:
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
await emailService.sendEmailWithTemplate({
|
|
274
|
+
templateId: "welcome",
|
|
275
|
+
to: "user@example.com",
|
|
276
|
+
variables: {
|
|
277
|
+
firstName: "John",
|
|
278
|
+
lastName: "Doe",
|
|
279
|
+
email: "john@example.com",
|
|
280
|
+
activationUrl: "https://yourdomain.com/activate/token123",
|
|
281
|
+
},
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
// Send import completion email
|
|
285
|
+
await emailService.sendEmailWithTemplate({
|
|
286
|
+
templateId: "import-completion",
|
|
287
|
+
to: "user@example.com",
|
|
288
|
+
variables: {
|
|
289
|
+
firstName: "John",
|
|
290
|
+
importSource: "Twitter Followers",
|
|
291
|
+
processedCount: 100,
|
|
292
|
+
matchedAccountCount: 50,
|
|
293
|
+
createdAccountCount: 30,
|
|
294
|
+
matchedPersonCount: 40,
|
|
295
|
+
createdPersonCount: 20,
|
|
296
|
+
edgeCreatedCount: 80,
|
|
297
|
+
rejectedCount: 5,
|
|
298
|
+
viewImportUrl: "https://yourdomain.com/imports/123",
|
|
299
|
+
},
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Available Templates
|
|
304
|
+
|
|
305
|
+
The library ships with no pre-built templates — define your own per-module.
|
|
306
|
+
|
|
307
|
+
### Creating Custom Templates
|
|
308
|
+
|
|
309
|
+
Templates live alongside the module that owns them, e.g. `modules/orders/templates/`:
|
|
310
|
+
|
|
311
|
+
**Step 1: Create the template file** (`modules/orders/templates/OrderConfirmationTemplate.ts`):
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
import type { EmailTemplate } from "@sixthsummit/ship-api/libraries/email";
|
|
315
|
+
import type { OrderConfirmationVariables } from "./types.js";
|
|
316
|
+
|
|
317
|
+
export const orderConfirmationTemplate: EmailTemplate<OrderConfirmationVariables> = {
|
|
318
|
+
id: "order-confirmation",
|
|
319
|
+
name: "Order Confirmation",
|
|
320
|
+
description: "Sent when a customer places an order",
|
|
321
|
+
subject: "Order Confirmation #{{orderNumber}}",
|
|
322
|
+
html: `
|
|
323
|
+
<h1>Thank you for your order, {{customerName}}!</h1>
|
|
324
|
+
<p>Order Number: {{orderNumber}}</p>
|
|
325
|
+
<p>Total: ${{total}}</p>
|
|
326
|
+
|
|
327
|
+
{{#if hasDiscount}}
|
|
328
|
+
<p>Discount Applied: {{discount}}%</p>
|
|
329
|
+
{{/if}}
|
|
330
|
+
|
|
331
|
+
<h2>Items:</h2>
|
|
332
|
+
<ul>
|
|
333
|
+
{{#each items}}
|
|
334
|
+
<li>{{this.name}} - ${{this.price}} x {{this.quantity}}</li>
|
|
335
|
+
{{/each}}
|
|
336
|
+
</ul>
|
|
337
|
+
`,
|
|
338
|
+
text: `...`,
|
|
339
|
+
tags: ["order", "confirmation"],
|
|
340
|
+
};
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
**Step 2: Define type-safe variables** (`modules/orders/templates/types.ts`):
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
export interface OrderConfirmationVariables {
|
|
347
|
+
customerName: string;
|
|
348
|
+
orderNumber: string;
|
|
349
|
+
total: number;
|
|
350
|
+
hasDiscount?: boolean;
|
|
351
|
+
discount?: number;
|
|
352
|
+
items: Array<{
|
|
353
|
+
name: string;
|
|
354
|
+
price: number;
|
|
355
|
+
quantity: number;
|
|
356
|
+
}>;
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
**Step 3: Export from module** (`modules/orders/templates/index.ts`):
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
import type { EmailTemplate } from "@sixthsummit/ship-api/libraries/email";
|
|
364
|
+
import { orderConfirmationTemplate } from "./OrderConfirmationTemplate.js";
|
|
365
|
+
|
|
366
|
+
export { orderConfirmationTemplate } from "./OrderConfirmationTemplate.js";
|
|
367
|
+
export * from "./types.js";
|
|
368
|
+
|
|
369
|
+
export const orderTemplates: EmailTemplate[] = [orderConfirmationTemplate];
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
**Step 4: Register at app startup** (`src/index.ts`):
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
import { EmailService } from "@sixthsummit/ship-api/libraries/email";
|
|
376
|
+
import { orderTemplates } from "./modules/orders/templates/index.js";
|
|
377
|
+
import { userTemplates } from "./modules/users/templates/index.js";
|
|
378
|
+
import { env } from "./environment.js";
|
|
379
|
+
|
|
380
|
+
const emailService = new EmailService(env.RESEND_API_KEY, env.RESEND_DEFAULT_FROM);
|
|
381
|
+
emailService.registerTemplates([...userTemplates, ...orderTemplates]);
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
**Step 5: Use the template**:
|
|
385
|
+
|
|
386
|
+
```typescript
|
|
387
|
+
await emailService.sendEmailWithTemplate({
|
|
388
|
+
templateId: "order-confirmation",
|
|
389
|
+
to: "customer@example.com",
|
|
390
|
+
variables: {
|
|
391
|
+
customerName: "Jane Smith",
|
|
392
|
+
orderNumber: "ORD-12345",
|
|
393
|
+
total: 99.99,
|
|
394
|
+
hasDiscount: true,
|
|
395
|
+
discount: 10,
|
|
396
|
+
items: [
|
|
397
|
+
{ name: "Product A", price: 49.99, quantity: 1 },
|
|
398
|
+
{ name: "Product B", price: 49.99, quantity: 1 },
|
|
399
|
+
],
|
|
400
|
+
},
|
|
401
|
+
});
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### Template Syntax
|
|
405
|
+
|
|
406
|
+
#### Variable Substitution
|
|
407
|
+
|
|
408
|
+
```typescript
|
|
409
|
+
// Simple variables
|
|
410
|
+
"Hello {{firstName}}!";
|
|
411
|
+
|
|
412
|
+
// Nested objects
|
|
413
|
+
"Email: {{user.email}}";
|
|
414
|
+
|
|
415
|
+
// Array indexing
|
|
416
|
+
"First item: {{items.0.name}}";
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
#### Conditionals
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
// Show content if variable is truthy
|
|
423
|
+
`{{#if showWelcome}}
|
|
424
|
+
<p>Welcome!</p>
|
|
425
|
+
{{/if}}`
|
|
426
|
+
// Nested conditionals
|
|
427
|
+
`{{#if user.isActive}}
|
|
428
|
+
<p>Active user</p>
|
|
429
|
+
{{/if}}`;
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
#### Loops
|
|
433
|
+
|
|
434
|
+
```typescript
|
|
435
|
+
// Iterate over array
|
|
436
|
+
`{{#each items}}
|
|
437
|
+
<li>{{this.name}}</li>
|
|
438
|
+
{{/each}}`
|
|
439
|
+
// Access loop variables
|
|
440
|
+
`{{#each items}}
|
|
441
|
+
<li>{{@index}}: {{this.name}}</li>
|
|
442
|
+
{{#if @first}}(First){{/if}}
|
|
443
|
+
{{#if @last}}(Last){{/if}}
|
|
444
|
+
{{/each}}`;
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
#### Helper Functions
|
|
448
|
+
|
|
449
|
+
```typescript
|
|
450
|
+
// Format numbers with commas
|
|
451
|
+
"Total: {{formatNumber count}}";
|
|
452
|
+
// Output: "Total: 1,000,000"
|
|
453
|
+
|
|
454
|
+
// Format dates
|
|
455
|
+
"Date: {{formatDate date}}";
|
|
456
|
+
// Output: "Date: January 15, 2025"
|
|
457
|
+
|
|
458
|
+
// Pluralize based on count
|
|
459
|
+
"{{count}} {{pluralize count 'item' 'items'}}";
|
|
460
|
+
// Output: "1 item" or "5 items"
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
### Batch Sending with Templates
|
|
464
|
+
|
|
465
|
+
```typescript
|
|
466
|
+
// Send multiple emails using templates
|
|
467
|
+
const results = await emailService.sendBatchEmailsWithTemplates([
|
|
468
|
+
{
|
|
469
|
+
templateId: "welcome",
|
|
470
|
+
to: "user1@example.com",
|
|
471
|
+
variables: { firstName: "John", lastName: "Doe", email: "user1@example.com" },
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
templateId: "welcome",
|
|
475
|
+
to: "user2@example.com",
|
|
476
|
+
variables: { firstName: "Jane", lastName: "Smith", email: "user2@example.com" },
|
|
477
|
+
},
|
|
478
|
+
]);
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### Template Management
|
|
482
|
+
|
|
483
|
+
```typescript
|
|
484
|
+
// Register a single template
|
|
485
|
+
emailService.registerTemplate(template);
|
|
486
|
+
|
|
487
|
+
// Register multiple templates
|
|
488
|
+
emailService.registerTemplates([template1, template2, template3]);
|
|
489
|
+
|
|
490
|
+
// Check if template exists
|
|
491
|
+
if (emailService.hasTemplate("welcome")) {
|
|
492
|
+
// Template is available
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Get a template
|
|
496
|
+
const template = emailService.getTemplate("welcome");
|
|
497
|
+
|
|
498
|
+
// List all templates
|
|
499
|
+
const allTemplates = emailService.listTemplates();
|
|
500
|
+
|
|
501
|
+
// Render template without sending (for preview)
|
|
502
|
+
const rendered = emailService.renderTemplate({
|
|
503
|
+
templateId: "welcome",
|
|
504
|
+
variables: { firstName: "John", lastName: "Doe", email: "john@example.com" },
|
|
505
|
+
});
|
|
506
|
+
console.log(rendered.subject); // "Welcome to ShipAPI App, John!"
|
|
507
|
+
console.log(rendered.html); // Rendered HTML
|
|
508
|
+
console.log(rendered.text); // Rendered text
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
### Template Organization Best Practices
|
|
512
|
+
|
|
513
|
+
1. **Module Ownership** - Each module owns its email templates
|
|
514
|
+
- User/auth templates: `modules/users/templates/`
|
|
515
|
+
- Import templates: `modules/imports/templates/`
|
|
516
|
+
- Order templates: `modules/orders/templates/`
|
|
517
|
+
|
|
518
|
+
2. **Type Safety** - Define interfaces for template variables in `types.ts`
|
|
519
|
+
|
|
520
|
+
3. **Centralized Registration** - Construct `EmailService` once in `src/index.ts` and register every module's templates against the same instance.
|
|
521
|
+
|
|
522
|
+
4. **Consistent Structure** - Each module's templates directory should have:
|
|
523
|
+
- Individual template files (`WelcomeTemplate.ts`)
|
|
524
|
+
- Type definitions (`types.ts`)
|
|
525
|
+
- Barrel export (`index.ts`)
|
|
526
|
+
|
|
527
|
+
### Why This Structure?
|
|
528
|
+
|
|
529
|
+
- **Cohesion**: Templates live with the domain logic they support
|
|
530
|
+
- **Modularity**: Removing a module removes its templates
|
|
531
|
+
- **Discoverability**: Easy to find templates related to a feature
|
|
532
|
+
- **Separation of Concerns**: Email library stays generic and reusable
|
|
533
|
+
- **Type Safety**: TypeScript ensures correct variable usage
|
|
534
|
+
|
|
535
|
+
### Error Handling
|
|
536
|
+
|
|
537
|
+
```typescript
|
|
538
|
+
const result = await emailService.sendEmail({
|
|
539
|
+
from: "noreply@yourdomain.com",
|
|
540
|
+
to: "user@example.com",
|
|
541
|
+
subject: "Welcome!",
|
|
542
|
+
text: "Welcome!",
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
if (result.error) {
|
|
546
|
+
console.error("Failed to send email:", result.error.message);
|
|
547
|
+
// Handle error (retry, log, notify, etc.)
|
|
548
|
+
} else {
|
|
549
|
+
console.log("Email sent successfully:", result.id);
|
|
550
|
+
// Store email ID for tracking
|
|
551
|
+
}
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
### Batch Error Handling
|
|
555
|
+
|
|
556
|
+
```typescript
|
|
557
|
+
const results = await emailService.sendBatchEmails({
|
|
558
|
+
emails: [...],
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
if (results.error) {
|
|
562
|
+
console.error("Batch send failed:", results.error.message);
|
|
563
|
+
} else {
|
|
564
|
+
results.data?.forEach((result, index) => {
|
|
565
|
+
console.log(`Email ${index} sent with ID: ${result.id}`);
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
## Common Use Cases
|
|
571
|
+
|
|
572
|
+
### Welcome Email
|
|
573
|
+
|
|
574
|
+
```typescript
|
|
575
|
+
async function sendWelcomeEmail(user: { email: string; name: string }) {
|
|
576
|
+
const emailService = new EmailService();
|
|
577
|
+
|
|
578
|
+
return await emailService.sendEmail({
|
|
579
|
+
from: "noreply@yourdomain.com",
|
|
580
|
+
to: { name: user.name, email: user.email },
|
|
581
|
+
subject: "Welcome to ShipAPI App!",
|
|
582
|
+
html: `
|
|
583
|
+
<h1>Welcome, ${user.name}!</h1>
|
|
584
|
+
<p>We're excited to have you on board.</p>
|
|
585
|
+
<p>Get started by logging in to your account.</p>
|
|
586
|
+
`,
|
|
587
|
+
tags: [
|
|
588
|
+
{ name: "type", value: "welcome" },
|
|
589
|
+
{ name: "user_id", value: user.id },
|
|
590
|
+
],
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
### Password Reset
|
|
596
|
+
|
|
597
|
+
```typescript
|
|
598
|
+
async function sendPasswordResetEmail(user: { email: string }, resetToken: string) {
|
|
599
|
+
const emailService = new EmailService();
|
|
600
|
+
const resetUrl = `https://yourdomain.com/reset-password?token=${resetToken}`;
|
|
601
|
+
|
|
602
|
+
return await emailService.sendEmail({
|
|
603
|
+
from: "noreply@yourdomain.com",
|
|
604
|
+
to: user.email,
|
|
605
|
+
replyTo: "support@yourdomain.com",
|
|
606
|
+
subject: "Password Reset Request",
|
|
607
|
+
html: `
|
|
608
|
+
<h1>Password Reset</h1>
|
|
609
|
+
<p>Click the link below to reset your password:</p>
|
|
610
|
+
<a href="${resetUrl}">Reset Password</a>
|
|
611
|
+
<p>This link will expire in 1 hour.</p>
|
|
612
|
+
<p>If you didn't request this, please ignore this email.</p>
|
|
613
|
+
`,
|
|
614
|
+
tags: [{ name: "type", value: "password_reset" }],
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
### Bulk User Notifications
|
|
620
|
+
|
|
621
|
+
```typescript
|
|
622
|
+
async function sendBulkNotifications(
|
|
623
|
+
users: Array<{ email: string; name: string }>,
|
|
624
|
+
message: string,
|
|
625
|
+
) {
|
|
626
|
+
const emailService = new EmailService();
|
|
627
|
+
|
|
628
|
+
// Split into batches of 100
|
|
629
|
+
const batches = [];
|
|
630
|
+
for (let i = 0; i < users.length; i += 100) {
|
|
631
|
+
batches.push(users.slice(i, i + 100));
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// Send each batch
|
|
635
|
+
for (const batch of batches) {
|
|
636
|
+
await emailService.sendBatchEmails({
|
|
637
|
+
emails: batch.map((user) => ({
|
|
638
|
+
from: "notifications@yourdomain.com",
|
|
639
|
+
to: { name: user.name, email: user.email },
|
|
640
|
+
subject: "Important Update",
|
|
641
|
+
html: `<p>Hi ${user.name},</p><p>${message}</p>`,
|
|
642
|
+
tags: [{ name: "type", value: "bulk_notification" }],
|
|
643
|
+
})),
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
## API Reference
|
|
650
|
+
|
|
651
|
+
### `EmailService`
|
|
652
|
+
|
|
653
|
+
#### Constructor
|
|
654
|
+
|
|
655
|
+
```typescript
|
|
656
|
+
new EmailService(
|
|
657
|
+
apiKey?: string,
|
|
658
|
+
defaultFrom?: string
|
|
659
|
+
)
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
- `apiKey` - Optional Resend API key (defaults to `RESEND_API_KEY` environment variable)
|
|
663
|
+
- `defaultFrom` - Optional default "from" email address
|
|
664
|
+
|
|
665
|
+
**Note**: Templates are not auto-registered. Construct `EmailService` once at app startup (in `src/index.ts`) and call `registerTemplates([...])` with each module's template list.
|
|
666
|
+
|
|
667
|
+
#### Methods
|
|
668
|
+
|
|
669
|
+
##### `sendEmail(options: SendEmailOptions): Promise<SendEmailResult>`
|
|
670
|
+
|
|
671
|
+
Send a single email.
|
|
672
|
+
|
|
673
|
+
##### `sendBatchEmails(options: SendBatchEmailsOptions): Promise<SendBatchEmailsResult>`
|
|
674
|
+
|
|
675
|
+
Send multiple emails in a batch (max 100).
|
|
676
|
+
|
|
677
|
+
##### `sendEmailWithTemplate<T>(options: RenderTemplateOptions<T> & EmailOptions): Promise<SendEmailResult>`
|
|
678
|
+
|
|
679
|
+
Send an email using a template.
|
|
680
|
+
|
|
681
|
+
##### `sendBatchEmailsWithTemplates<T>(emails: Array<...>): Promise<SendBatchEmailsResult>`
|
|
682
|
+
|
|
683
|
+
Send multiple emails using templates.
|
|
684
|
+
|
|
685
|
+
##### `registerTemplate<T>(template: EmailTemplate<T>): void`
|
|
686
|
+
|
|
687
|
+
Register an email template.
|
|
688
|
+
|
|
689
|
+
##### `registerTemplates(templates: EmailTemplate[]): void`
|
|
690
|
+
|
|
691
|
+
Register multiple email templates.
|
|
692
|
+
|
|
693
|
+
##### `getTemplate(id: string): EmailTemplate | undefined`
|
|
694
|
+
|
|
695
|
+
Get a registered template by ID.
|
|
696
|
+
|
|
697
|
+
##### `listTemplates(): EmailTemplate[]`
|
|
698
|
+
|
|
699
|
+
List all registered templates.
|
|
700
|
+
|
|
701
|
+
##### `hasTemplate(id: string): boolean`
|
|
702
|
+
|
|
703
|
+
Check if a template exists.
|
|
704
|
+
|
|
705
|
+
##### `renderTemplate<T>(options: RenderTemplateOptions<T>): RenderedTemplate`
|
|
706
|
+
|
|
707
|
+
Render a template with variables (without sending).
|
|
708
|
+
|
|
709
|
+
##### `getDefaultFrom(): string`
|
|
710
|
+
|
|
711
|
+
Get the default from address.
|
|
712
|
+
|
|
713
|
+
##### `setDefaultFrom(defaultFrom: string): void`
|
|
714
|
+
|
|
715
|
+
Set the default from address.
|
|
716
|
+
|
|
717
|
+
### Types
|
|
718
|
+
|
|
719
|
+
See [types/index.ts](./types/index.ts) for detailed type definitions.
|
|
720
|
+
|
|
721
|
+
## Best Practices
|
|
722
|
+
|
|
723
|
+
### Email Sending
|
|
724
|
+
|
|
725
|
+
1. **Use Verified Domains** - Always send from verified domains to ensure deliverability
|
|
726
|
+
2. **Handle Errors** - Always check for errors in the response and handle them appropriately
|
|
727
|
+
3. **Use Tags** - Add tags to track email types and measure performance
|
|
728
|
+
4. **Batch When Possible** - Use batch sending for better performance when sending multiple emails
|
|
729
|
+
5. **Set Reply-To** - Always provide a reply-to address for customer support
|
|
730
|
+
6. **Test Thoroughly** - Test emails in development before sending to production
|
|
731
|
+
7. **Monitor Delivery** - Use Resend's dashboard to monitor email delivery and engagement
|
|
732
|
+
|
|
733
|
+
### Template Usage
|
|
734
|
+
|
|
735
|
+
8. **Use Templates** - Leverage templates for consistent branding and easier maintenance
|
|
736
|
+
9. **Single Instance** - Construct `EmailService` once at app startup and inject it into the modules / jobs that need it; don't reconstruct per request
|
|
737
|
+
10. **Type-Safe Variables** - Define interfaces for template variables to catch errors at compile time
|
|
738
|
+
11. **Preview Templates** - Use `renderTemplate()` to preview emails before sending
|
|
739
|
+
12. **Organize Templates** - Keep templates in their respective module directories
|
|
740
|
+
13. **Version Control** - Keep templates in version control for tracking changes
|
|
741
|
+
14. **Module Ownership** - Each module should own and maintain its email templates
|
|
742
|
+
|
|
743
|
+
## Testing
|
|
744
|
+
|
|
745
|
+
When testing in development:
|
|
746
|
+
|
|
747
|
+
1. Use Resend's test mode or a test domain
|
|
748
|
+
2. Send to your own email addresses
|
|
749
|
+
3. Check Resend dashboard for delivery status
|
|
750
|
+
4. Verify email content in your inbox
|
|
751
|
+
|
|
752
|
+
## Troubleshooting
|
|
753
|
+
|
|
754
|
+
### "From address is required"
|
|
755
|
+
|
|
756
|
+
Make sure you either:
|
|
757
|
+
|
|
758
|
+
- Provide a `from` address in `sendEmail()` options
|
|
759
|
+
- Set a default from address in the constructor
|
|
760
|
+
- Set `RESEND_DEFAULT_FROM` environment variable
|
|
761
|
+
|
|
762
|
+
### "Resend API key is required"
|
|
763
|
+
|
|
764
|
+
Make sure you have set the `RESEND_API_KEY` environment variable.
|
|
765
|
+
|
|
766
|
+
### Email not delivered
|
|
767
|
+
|
|
768
|
+
1. Check Resend dashboard for delivery status
|
|
769
|
+
2. Verify your domain is properly configured
|
|
770
|
+
3. Check spam folders
|
|
771
|
+
4. Ensure recipient email addresses are valid
|
|
772
|
+
|
|
773
|
+
## Resources
|
|
774
|
+
|
|
775
|
+
- [Resend Documentation](https://resend.com/docs)
|
|
776
|
+
- [Resend API Reference](https://resend.com/docs/api-reference)
|
|
777
|
+
- [Resend Node.js SDK](https://github.com/resendlabs/resend-node)
|