tempest-express-sdk 0.9.0 → 0.10.0

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/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { VERSION } from './chunk-4QZZGHGV.js';
1
+ export { VERSION } from './chunk-U3SXT3KR.js';
2
2
  import { AsyncLocalStorage } from 'async_hooks';
3
3
  import { extendZodWithOpenApi, OpenAPIRegistry, OpenApiGeneratorV31, OpenApiGeneratorV3 } from '@asteasolutions/zod-to-openapi';
4
4
  export { OpenAPIRegistry } from '@asteasolutions/zod-to-openapi';
@@ -8581,6 +8581,50 @@ function makeTwilioWebhookRouter(options) {
8581
8581
  return router;
8582
8582
  }
8583
8583
 
8584
+ // src/integrations/email.ts
8585
+ var EmailProvider = class {
8586
+ email;
8587
+ subject;
8588
+ /**
8589
+ * @param options - The email sender and default subject.
8590
+ */
8591
+ constructor(options) {
8592
+ this.email = options.email;
8593
+ this.subject = options.subject ?? "Notification";
8594
+ }
8595
+ /**
8596
+ * Send a plain-text email.
8597
+ *
8598
+ * @param to - Recipient address.
8599
+ * @param text - Body text (also used as HTML).
8600
+ * @returns A sent result.
8601
+ */
8602
+ async sendText(to, text) {
8603
+ await this.email.send({ to, subject: this.subject, text });
8604
+ return { status: "sent" };
8605
+ }
8606
+ /**
8607
+ * Send an email linking to the media (caption becomes the lead text).
8608
+ *
8609
+ * @param to - Recipient address.
8610
+ * @param media - The media reference (URL) + optional caption.
8611
+ * @returns A sent result.
8612
+ */
8613
+ async sendMedia(to, media) {
8614
+ const caption = media.caption ?? "";
8615
+ await this.email.send({
8616
+ to,
8617
+ subject: this.subject,
8618
+ html: `${caption ? `<p>${caption}</p>` : ""}<p><a href="${media.media}">${media.media}</a></p>`
8619
+ });
8620
+ return { status: "sent" };
8621
+ }
8622
+ /** Always `"connected"` — SMTP reachability is verified on first send. */
8623
+ async status() {
8624
+ return "connected";
8625
+ }
8626
+ };
8627
+
8584
8628
  // src/admin/site.ts
8585
8629
  var AdminSite = class {
8586
8630
  /**
@@ -8720,6 +8764,10 @@ var mfaEnrollResponseSchema = z.object({
8720
8764
  otpauthUri: z.string().openapi({ description: "otpauth:// URI to render as QR." })
8721
8765
  }).openapi("MfaEnrollResponse");
8722
8766
  var mfaCodeSchema = z.object({ code: z.string().min(1).openapi({ description: "Authenticator code." }) }).openapi("MfaCode");
8767
+ var mfaChallengeSchema = z.object({
8768
+ mfaToken: z.string().min(1).openapi({ description: "Challenge token from login." }),
8769
+ code: z.string().min(1).openapi({ description: "Authenticator code." })
8770
+ }).openapi("MfaChallenge");
8723
8771
  var activationSchema = z.object({ token: z.string().min(1).openapi({ description: "Activation token." }) }).openapi("Activation");
8724
8772
  var passwordResetRequestSchema = z.object({ email: z.string().email().openapi({ description: "Account email." }) }).openapi("PasswordResetRequest");
8725
8773
  var passwordResetConfirmSchema = z.object({
@@ -8744,6 +8792,8 @@ var UserAuthService = class {
8744
8792
  passwordMinLength;
8745
8793
  accessTtlSeconds;
8746
8794
  refreshTtlSeconds;
8795
+ mfa;
8796
+ mfaChallengeTtlSeconds;
8747
8797
  /**
8748
8798
  * @param options - Store, password/JWT helpers and token policy.
8749
8799
  */
@@ -8754,6 +8804,8 @@ var UserAuthService = class {
8754
8804
  this.passwordMinLength = options.passwordMinLength ?? 12;
8755
8805
  this.accessTtlSeconds = options.accessTtlSeconds ?? 3600;
8756
8806
  this.refreshTtlSeconds = options.refreshTtlSeconds ?? 60 * 60 * 24 * 14;
8807
+ this.mfa = options.mfa;
8808
+ this.mfaChallengeTtlSeconds = options.mfaChallengeTtlSeconds ?? 300;
8757
8809
  }
8758
8810
  /** Mint a signed access + refresh token pair for `user`. */
8759
8811
  async issueTokens(user) {
@@ -8803,7 +8855,7 @@ var UserAuthService = class {
8803
8855
  * Authenticate a user by email + password.
8804
8856
  *
8805
8857
  * @param data - Validated login payload.
8806
- * @returns The public user and a fresh token pair.
8858
+ * @returns Full auth, or an {@link MfaChallenge} when MFA is enabled.
8807
8859
  * @throws {UnauthorizedException} On bad credentials or inactive account.
8808
8860
  */
8809
8861
  async login(data) {
@@ -8815,6 +8867,37 @@ var UserAuthService = class {
8815
8867
  if (!user.isActive) {
8816
8868
  throw new UnauthorizedException({ message: "Account is inactive" });
8817
8869
  }
8870
+ if (this.mfa && await this.mfa.isEnabled(user.id)) {
8871
+ const mfaToken = await this.jwt.encode(
8872
+ { sub: user.id, type: "mfa" },
8873
+ { ttlSeconds: this.mfaChallengeTtlSeconds }
8874
+ );
8875
+ return { mfaRequired: true, mfaToken };
8876
+ }
8877
+ return { user: toPublic(user), tokens: await this.issueTokens(user) };
8878
+ }
8879
+ /**
8880
+ * Complete an MFA login challenge: verify the code and issue tokens.
8881
+ *
8882
+ * @param mfaToken - The challenge token from {@link login}.
8883
+ * @param code - The authenticator code.
8884
+ * @returns The public user and a fresh token pair.
8885
+ * @throws {UnauthorizedException} When the challenge/code is invalid, MFA is
8886
+ * not configured, or the account no longer exists / is inactive.
8887
+ */
8888
+ async verifyMfaChallenge(mfaToken, code) {
8889
+ if (!this.mfa) throw new UnauthorizedException({ message: "MFA not configured" });
8890
+ const claims = await this.jwt.decodeOrNull(mfaToken);
8891
+ if (!claims || claims.type !== "mfa" || typeof claims.sub !== "string") {
8892
+ throw new UnauthorizedException({ message: "Invalid MFA challenge" });
8893
+ }
8894
+ if (!await this.mfa.verify(claims.sub, code)) {
8895
+ throw new UnauthorizedException({ message: "Invalid MFA code" });
8896
+ }
8897
+ const user = await this.store.findById(claims.sub);
8898
+ if (!user || !user.isActive) {
8899
+ throw new UnauthorizedException({ message: "Account is inactive" });
8900
+ }
8818
8901
  return { user: toPublic(user), tokens: await this.issueTokens(user) };
8819
8902
  }
8820
8903
  /**
@@ -8888,6 +8971,15 @@ var MfaService = class {
8888
8971
  const secret = await this.store.getSecret(userId);
8889
8972
  return secret ? this.totp.verify(secret, code) : false;
8890
8973
  }
8974
+ /**
8975
+ * Whether MFA is enabled for a user (used to gate the login challenge).
8976
+ *
8977
+ * @param userId - The user.
8978
+ * @returns `true` when MFA is enabled.
8979
+ */
8980
+ async isEnabled(userId) {
8981
+ return this.store.isEnabled(userId);
8982
+ }
8891
8983
  /**
8892
8984
  * Disable MFA after verifying a code.
8893
8985
  *
@@ -9135,6 +9227,10 @@ function makeAuthRouter(options) {
9135
9227
  }
9136
9228
  if (options.mfa) {
9137
9229
  const mfa = options.mfa;
9230
+ router.post(`${prefix}/mfa/challenge`, async (req, res) => {
9231
+ const { mfaToken, code } = mfaChallengeSchema.parse(req.body);
9232
+ res.json(await service.verifyMfaChallenge(mfaToken, code));
9233
+ });
9138
9234
  const requireUser = (req) => {
9139
9235
  const claims = getAuth(req);
9140
9236
  if (!claims || typeof claims.sub !== "string") {
@@ -9436,6 +9532,6 @@ function runServer(app, options = {}) {
9436
9532
  });
9437
9533
  }
9438
9534
 
9439
- export { ActivationService, AdminSite, AppException, AttemptThrottle, BaseController, BaseModel, BaseService, CEP_PATTERN, CNPJ_PATTERN, CPF_PATTERN, CircuitOpenError, CompositeFeatureFlagBackend, ConflictException, DEFAULT_LOCALE, EmailUtils, EnvFeatureFlagBackend, EventStream, ExpiredTokenException, FeatureFlags, ForbiddenException, HTTPClient, HTTP_500_MARKER, InvalidTokenException, JSONLogger, JWTUtils, LocalUploadStorage, MemoryBroker, MemoryCacheManager, MemoryFeatureFlagBackend, MemorySessionStore, MemoryThrottleBackend, MessageCatalog, MetricsUtils, MfaService, NotFoundException, PHONE_BR_PATTERN, PasswordResetService, PasswordUtils, REQUEST_ID_HEADER, RabbitBroker, RedisCacheManager, RedisSSEBroker, RedisSessionStore, Region, RetryPolicy, SSEBroker, ServerSentEvent, SessionService, TOTPHelper, TaskManager, TelegramProvider, TooManyRequestsException, TwilioSmsProvider, UF, UnauthorizedException, UserAuthService, ValidationException, WebPushDispatcher, WebPushError, WebPushGoneError, WebSocketHub, WhatsAppProvider, activationSchema, attachWebSocketHub, authResponseSchema, baseAppSettingsSchema, baseAppSettingsShape, baseResponseSchema, bearerToken, buildContentDisposition, cached3 as cached, cepField, citiesByUf, cnpjField, coerceFlag, configureLogging, corsSettingsShape, cpfField, cpfOrCnpjField, createApp, createOpenApiRegistry, createdByColumn, cursorPaginationFilterSchema, cursorPaginationSchema, databaseSettingsShape, decodeCursor, defaultMessageCatalog, defineEnum, deletedAtColumn, encodeCursor, generateOpaqueToken, generateOpenApiDocument, getAuth, getClientIp, getConditions, getPaginationConditions, getRequestId, getState, hashOpaqueToken, inboundMessageSchema, isValidCep, isValidCity, isValidCnpj, isValidCpf, isValidCpfCnpj, isValidPhoneBr, isValidUf, listStates, loadSettings, loginSchema, makeAdminRouter, makeAppExceptionHandler, makeAuthRouter, makeFlagGuard, makeHealthRouter, makeJwtAuthMiddleware, makeMetricsRouter, makeSessionMiddleware, makeTwilioWebhookRouter, makeUnhandledExceptionHandler, makeWhatsAppWebhookRouter, mfaCodeSchema, mfaEnrollResponseSchema, modifyDict, mountOpenApiJson, mountRedoc, mountSwaggerUi, normalizeCep, normalizeCnpj, normalizeCpf, normalizeCpfCnpj, normalizePhoneBr, normalizeUf, notFoundHandler, onlyDigits, paginationFilterSchema, paginationSchema, parseAcceptLanguage, parseCookies, passwordResetConfirmSchema, passwordResetRequestSchema, phoneBrField, refreshSchema, registerExceptionHandlers, requestIdMiddleware, requireRoles, runServer, runWithRequestContext, serverSettingsShape, sessionCookie, setRequestId, signupSchema, sseResponse, statesByRegion, tableNameFor, toDict, toUtc, tokenFromUrl, tokenPairSchema, ufField, updatedByColumn, userPublicSchema, utcnow, validateTwilioSignature, verifyOpaqueToken, webPushKeysSchema, webPushPayloadSchema, webPushSubscriptionSchema, wsEnvelopeSchema };
9535
+ export { ActivationService, AdminSite, AppException, AttemptThrottle, BaseController, BaseModel, BaseService, CEP_PATTERN, CNPJ_PATTERN, CPF_PATTERN, CircuitOpenError, CompositeFeatureFlagBackend, ConflictException, DEFAULT_LOCALE, EmailProvider, EmailUtils, EnvFeatureFlagBackend, EventStream, ExpiredTokenException, FeatureFlags, ForbiddenException, HTTPClient, HTTP_500_MARKER, InvalidTokenException, JSONLogger, JWTUtils, LocalUploadStorage, MemoryBroker, MemoryCacheManager, MemoryFeatureFlagBackend, MemorySessionStore, MemoryThrottleBackend, MessageCatalog, MetricsUtils, MfaService, NotFoundException, PHONE_BR_PATTERN, PasswordResetService, PasswordUtils, REQUEST_ID_HEADER, RabbitBroker, RedisCacheManager, RedisSSEBroker, RedisSessionStore, Region, RetryPolicy, SSEBroker, ServerSentEvent, SessionService, TOTPHelper, TaskManager, TelegramProvider, TooManyRequestsException, TwilioSmsProvider, UF, UnauthorizedException, UserAuthService, ValidationException, WebPushDispatcher, WebPushError, WebPushGoneError, WebSocketHub, WhatsAppProvider, activationSchema, attachWebSocketHub, authResponseSchema, baseAppSettingsSchema, baseAppSettingsShape, baseResponseSchema, bearerToken, buildContentDisposition, cached3 as cached, cepField, citiesByUf, cnpjField, coerceFlag, configureLogging, corsSettingsShape, cpfField, cpfOrCnpjField, createApp, createOpenApiRegistry, createdByColumn, cursorPaginationFilterSchema, cursorPaginationSchema, databaseSettingsShape, decodeCursor, defaultMessageCatalog, defineEnum, deletedAtColumn, encodeCursor, generateOpaqueToken, generateOpenApiDocument, getAuth, getClientIp, getConditions, getPaginationConditions, getRequestId, getState, hashOpaqueToken, inboundMessageSchema, isValidCep, isValidCity, isValidCnpj, isValidCpf, isValidCpfCnpj, isValidPhoneBr, isValidUf, listStates, loadSettings, loginSchema, makeAdminRouter, makeAppExceptionHandler, makeAuthRouter, makeFlagGuard, makeHealthRouter, makeJwtAuthMiddleware, makeMetricsRouter, makeSessionMiddleware, makeTwilioWebhookRouter, makeUnhandledExceptionHandler, makeWhatsAppWebhookRouter, mfaChallengeSchema, mfaCodeSchema, mfaEnrollResponseSchema, modifyDict, mountOpenApiJson, mountRedoc, mountSwaggerUi, normalizeCep, normalizeCnpj, normalizeCpf, normalizeCpfCnpj, normalizePhoneBr, normalizeUf, notFoundHandler, onlyDigits, paginationFilterSchema, paginationSchema, parseAcceptLanguage, parseCookies, passwordResetConfirmSchema, passwordResetRequestSchema, phoneBrField, refreshSchema, registerExceptionHandlers, requestIdMiddleware, requireRoles, runServer, runWithRequestContext, serverSettingsShape, sessionCookie, setRequestId, signupSchema, sseResponse, statesByRegion, tableNameFor, toDict, toUtc, tokenFromUrl, tokenPairSchema, ufField, updatedByColumn, userPublicSchema, utcnow, validateTwilioSignature, verifyOpaqueToken, webPushKeysSchema, webPushPayloadSchema, webPushSubscriptionSchema, wsEnvelopeSchema };
9440
9536
  //# sourceMappingURL=index.js.map
9441
9537
  //# sourceMappingURL=index.js.map