tempest-express-sdk 0.3.0 → 0.5.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-6ZKN2ELQ.js';
1
+ export { VERSION } from './chunk-ZU6W433I.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';
@@ -8026,6 +8026,278 @@ var WebPushDispatcher = class {
8026
8026
  }
8027
8027
  };
8028
8028
 
8029
+ // src/integrations/provider.ts
8030
+ var inboundMessageSchema = z.object({
8031
+ /** Conversation JID / sender (e.g. `5511999999999@s.whatsapp.net`). */
8032
+ from: z.string().openapi({ description: "Conversation JID / sender." }),
8033
+ /** Provider message id. */
8034
+ messageId: z.string().openapi({ description: "Provider message id." }),
8035
+ /** Text body, when present. */
8036
+ text: z.string().optional().openapi({ description: "Text body." }),
8037
+ /** Media kind, or `null` for plain text. */
8038
+ mediaType: z.enum(["image", "video", "audio", "document", "sticker"]).nullable().openapi({ description: "Media kind, or null for text." }),
8039
+ /** ISO-8601 timestamp. */
8040
+ timestamp: z.string().openapi({ description: "ISO-8601 timestamp." }),
8041
+ /** Delivery direction. */
8042
+ direction: z.enum(["incoming", "outgoing"]).optional()
8043
+ }).openapi("InboundMessage");
8044
+
8045
+ // src/integrations/whatsapp.ts
8046
+ var MEDIA_ROUTE = {
8047
+ image: "send-image",
8048
+ video: "send-video",
8049
+ audio: "send-audio",
8050
+ document: "send-document"
8051
+ };
8052
+ function deriveWsUrl(baseUrl) {
8053
+ const trimmed = baseUrl.replace(/\/$/, "");
8054
+ return `${trimmed.replace(/^http/, "ws")}/ws`;
8055
+ }
8056
+ var WhatsAppProvider = class {
8057
+ http;
8058
+ apiKey;
8059
+ wsUrl;
8060
+ /**
8061
+ * @param options - Base URL, API key and optional WebSocket URL.
8062
+ */
8063
+ constructor(options) {
8064
+ this.apiKey = options.apiKey;
8065
+ this.wsUrl = options.wsUrl ?? deriveWsUrl(options.baseUrl);
8066
+ this.http = new HTTPClient({
8067
+ baseUrl: options.baseUrl.replace(/\/$/, ""),
8068
+ defaultHeaders: { "x-api-key": options.apiKey, "content-type": "application/json" },
8069
+ timeoutMs: options.timeoutMs ?? 15e3
8070
+ });
8071
+ }
8072
+ /** POST JSON and parse the response, throwing on a non-2xx status. */
8073
+ async postJson(path, body, options) {
8074
+ const headers = options?.idempotencyKey ? { "Idempotency-Key": options.idempotencyKey } : void 0;
8075
+ const res = await this.http.post(path, {
8076
+ body: JSON.stringify(body),
8077
+ ...headers ? { headers } : {}
8078
+ });
8079
+ const data = await res.json().catch(() => ({}));
8080
+ if (!res.ok) {
8081
+ throw new Error(
8082
+ `zap-api ${path} failed (${res.status}): ${String(data.error ?? res.statusText)}`
8083
+ );
8084
+ }
8085
+ return data;
8086
+ }
8087
+ async sendText(to, text, options) {
8088
+ const data = await this.postJson("/message/send-text", { to, text }, options);
8089
+ return {
8090
+ status: String(data.status ?? "queued"),
8091
+ ...typeof data.id === "string" ? { id: data.id } : {},
8092
+ ...typeof data.deduped === "boolean" ? { deduped: data.deduped } : {}
8093
+ };
8094
+ }
8095
+ async sendMedia(to, media, options) {
8096
+ const body = { to, media: media.media };
8097
+ if (media.caption !== void 0) body.caption = media.caption;
8098
+ if (media.fileName !== void 0) body.fileName = media.fileName;
8099
+ const data = await this.postJson(
8100
+ `/message/${MEDIA_ROUTE[media.kind]}`,
8101
+ body,
8102
+ options
8103
+ );
8104
+ return {
8105
+ status: String(data.status ?? "queued"),
8106
+ ...typeof data.id === "string" ? { id: data.id } : {},
8107
+ ...typeof data.deduped === "boolean" ? { deduped: data.deduped } : {}
8108
+ };
8109
+ }
8110
+ async checkNumber(number) {
8111
+ const res = await this.http.get(
8112
+ `/message/check-number/${encodeURIComponent(number)}`
8113
+ );
8114
+ const data = await res.json().catch(() => ({}));
8115
+ return data.exists === true;
8116
+ }
8117
+ async status() {
8118
+ const res = await this.http.get("/session/status");
8119
+ const raw = await res.text();
8120
+ try {
8121
+ const parsed = JSON.parse(raw);
8122
+ return parsed.status ?? raw.trim();
8123
+ } catch {
8124
+ return raw.trim();
8125
+ }
8126
+ }
8127
+ /** Start the WhatsApp session (returns the authenticated QR URL, if any). */
8128
+ async startSession() {
8129
+ return this.postJson("/session/start", {});
8130
+ }
8131
+ async onMessage(handler, room = "*") {
8132
+ let ws;
8133
+ try {
8134
+ ws = await import('ws');
8135
+ } catch (cause) {
8136
+ throw new Error(
8137
+ "WhatsAppProvider.onMessage requires the 'ws' peer dependency. Install with `npm i ws`.",
8138
+ { cause }
8139
+ );
8140
+ }
8141
+ const socket = new ws.WebSocket(this.wsUrl, {
8142
+ headers: { "x-api-key": this.apiKey }
8143
+ });
8144
+ socket.on("open", () => {
8145
+ socket.send(JSON.stringify({ action: "subscribe", room }));
8146
+ });
8147
+ socket.on("message", (raw) => {
8148
+ let frame;
8149
+ try {
8150
+ frame = JSON.parse(String(raw));
8151
+ } catch {
8152
+ return;
8153
+ }
8154
+ if (frame.type === "message" && frame.payload) {
8155
+ const p = frame.payload;
8156
+ void handler({
8157
+ from: String(p.remoteJid ?? ""),
8158
+ messageId: String(p.messageId ?? ""),
8159
+ ...typeof p.text === "string" ? { text: p.text } : {},
8160
+ mediaType: p.mediaType ?? null,
8161
+ timestamp: String(p.timestamp ?? ""),
8162
+ ...p.direction === "incoming" || p.direction === "outgoing" ? { direction: p.direction } : {}
8163
+ });
8164
+ }
8165
+ });
8166
+ return async () => {
8167
+ try {
8168
+ socket.send(JSON.stringify({ action: "unsubscribe", room }));
8169
+ } catch {
8170
+ }
8171
+ socket.close();
8172
+ };
8173
+ }
8174
+ };
8175
+ function safeEqual(a, b) {
8176
+ const bufA = Buffer.from(a);
8177
+ const bufB = Buffer.from(b);
8178
+ return bufA.length === bufB.length && timingSafeEqual(bufA, bufB);
8179
+ }
8180
+ function makeWhatsAppWebhookRouter(options) {
8181
+ const path = options.path ?? "/whatsapp/inbound";
8182
+ const router = Router();
8183
+ router.post(path, async (req, res) => {
8184
+ if (options.apiKey) {
8185
+ const provided = req.header("x-api-key") ?? "";
8186
+ if (!safeEqual(provided, options.apiKey)) {
8187
+ throw new UnauthorizedException({ message: "Invalid webhook key" });
8188
+ }
8189
+ }
8190
+ const message = inboundMessageSchema.parse(req.body);
8191
+ await options.onMessage(message);
8192
+ res.status(200).json({ ok: true });
8193
+ });
8194
+ return router;
8195
+ }
8196
+
8197
+ // src/admin/site.ts
8198
+ var AdminSite = class {
8199
+ /**
8200
+ * @param brand - Display name surfaced under `GET {prefix}/`.
8201
+ */
8202
+ constructor(brand = "Admin") {
8203
+ this.brand = brand;
8204
+ }
8205
+ brand;
8206
+ resources = /* @__PURE__ */ new Map();
8207
+ /**
8208
+ * Register a resource.
8209
+ *
8210
+ * @param resource - The resource config.
8211
+ * @returns The same resource (for chaining).
8212
+ */
8213
+ register(resource) {
8214
+ this.resources.set(resource.name, resource);
8215
+ return resource;
8216
+ }
8217
+ /** Look up a resource by slug, or `null`. */
8218
+ get(name) {
8219
+ return this.resources.get(name) ?? null;
8220
+ }
8221
+ /** Every registered resource. */
8222
+ list() {
8223
+ return [...this.resources.values()];
8224
+ }
8225
+ };
8226
+ var PAGINATION_KEYS2 = /* @__PURE__ */ new Set(["page", "pageSize"]);
8227
+ function methodNotAllowed(operation) {
8228
+ return new AppException({
8229
+ message: `Operation not allowed: ${operation}`,
8230
+ code: "METHOD_NOT_ALLOWED",
8231
+ statusCode: 405
8232
+ });
8233
+ }
8234
+ function requireResource(site, name) {
8235
+ const resource = site.get(name);
8236
+ if (!resource) throw new NotFoundException({ message: `Unknown resource: ${name}` });
8237
+ return resource;
8238
+ }
8239
+ function makeAdminRouter(site, options = {}) {
8240
+ const prefix = (options.prefix ?? "/admin").replace(/\/$/, "");
8241
+ const router = Router();
8242
+ if (options.guard) router.use(prefix, options.guard);
8243
+ router.get(prefix, (_req, res) => {
8244
+ res.json({
8245
+ brand: site.brand,
8246
+ resources: site.list().map((r) => ({ name: r.name, fields: r.fields }))
8247
+ });
8248
+ });
8249
+ router.get(`${prefix}/:resource/_meta`, (req, res) => {
8250
+ const resource = requireResource(site, req.params.resource);
8251
+ res.json({
8252
+ name: resource.name,
8253
+ fields: resource.fields,
8254
+ operations: {
8255
+ create: Boolean(resource.create),
8256
+ update: Boolean(resource.update),
8257
+ remove: Boolean(resource.remove)
8258
+ }
8259
+ });
8260
+ });
8261
+ router.get(`${prefix}/:resource`, async (req, res) => {
8262
+ const resource = requireResource(site, req.params.resource);
8263
+ const filters = {};
8264
+ for (const [key, value] of Object.entries(req.query)) {
8265
+ if (!PAGINATION_KEYS2.has(key) && typeof value === "string") filters[key] = value;
8266
+ }
8267
+ const page = Math.max(1, Number.parseInt(String(req.query.page ?? "1"), 10) || 1);
8268
+ const pageSize = Math.max(
8269
+ 1,
8270
+ Number.parseInt(String(req.query.pageSize ?? "20"), 10) || 20
8271
+ );
8272
+ res.json(await resource.list({ page, pageSize, filters }));
8273
+ });
8274
+ router.get(`${prefix}/:resource/:id`, async (req, res) => {
8275
+ const resource = requireResource(site, req.params.resource);
8276
+ const record = await resource.get(req.params.id);
8277
+ if (record === null) throw new NotFoundException({ message: "Record not found" });
8278
+ res.json(record);
8279
+ });
8280
+ router.post(`${prefix}/:resource`, async (req, res) => {
8281
+ const resource = requireResource(site, req.params.resource);
8282
+ if (!resource.create) throw methodNotAllowed("create");
8283
+ const data = resource.createSchema ? resource.createSchema.parse(req.body) : req.body;
8284
+ res.status(201).json(await resource.create(data));
8285
+ });
8286
+ router.patch(`${prefix}/:resource/:id`, async (req, res) => {
8287
+ const resource = requireResource(site, req.params.resource);
8288
+ if (!resource.update) throw methodNotAllowed("update");
8289
+ const data = resource.updateSchema ? resource.updateSchema.parse(req.body) : req.body;
8290
+ res.json(await resource.update(req.params.id, data));
8291
+ });
8292
+ router.delete(`${prefix}/:resource/:id`, async (req, res) => {
8293
+ const resource = requireResource(site, req.params.resource);
8294
+ if (!resource.remove) throw methodNotAllowed("remove");
8295
+ await resource.remove(req.params.id);
8296
+ res.status(204).end();
8297
+ });
8298
+ return router;
8299
+ }
8300
+
8029
8301
  // src/auth/schemas.ts
8030
8302
  var signupSchema = z.object({
8031
8303
  email: z.string().email().openapi({ description: "Login identifier (email)." }),
@@ -8537,6 +8809,6 @@ function runServer(app, options = {}) {
8537
8809
  });
8538
8810
  }
8539
8811
 
8540
- export { 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, NotFoundException, PHONE_BR_PATTERN, PasswordUtils, REQUEST_ID_HEADER, RabbitBroker, RedisCacheManager, Region, RetryPolicy, SSEBroker, ServerSentEvent, SessionService, TOTPHelper, TaskManager, TooManyRequestsException, UF, UnauthorizedException, UserAuthService, ValidationException, WebPushDispatcher, WebPushError, WebPushGoneError, WebSocketHub, 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, isValidCep, isValidCity, isValidCnpj, isValidCpf, isValidCpfCnpj, isValidPhoneBr, isValidUf, listStates, loadSettings, loginSchema, makeAppExceptionHandler, makeAuthRouter, makeFlagGuard, makeHealthRouter, makeJwtAuthMiddleware, makeSessionMiddleware, makeUnhandledExceptionHandler, modifyDict, mountOpenApiJson, mountRedoc, mountSwaggerUi, normalizeCep, normalizeCnpj, normalizeCpf, normalizeCpfCnpj, normalizePhoneBr, normalizeUf, notFoundHandler, onlyDigits, paginationFilterSchema, paginationSchema, parseAcceptLanguage, parseCookies, phoneBrField, refreshSchema, registerExceptionHandlers, requestIdMiddleware, requireRoles, runServer, runWithRequestContext, serverSettingsShape, sessionCookie, setRequestId, signupSchema, sseResponse, statesByRegion, tableNameFor, toDict, toUtc, tokenFromUrl, tokenPairSchema, ufField, updatedByColumn, userPublicSchema, utcnow, verifyOpaqueToken, webPushKeysSchema, webPushPayloadSchema, webPushSubscriptionSchema, wsEnvelopeSchema };
8812
+ export { 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, NotFoundException, PHONE_BR_PATTERN, PasswordUtils, REQUEST_ID_HEADER, RabbitBroker, RedisCacheManager, Region, RetryPolicy, SSEBroker, ServerSentEvent, SessionService, TOTPHelper, TaskManager, TooManyRequestsException, UF, UnauthorizedException, UserAuthService, ValidationException, WebPushDispatcher, WebPushError, WebPushGoneError, WebSocketHub, WhatsAppProvider, 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, makeSessionMiddleware, makeUnhandledExceptionHandler, makeWhatsAppWebhookRouter, modifyDict, mountOpenApiJson, mountRedoc, mountSwaggerUi, normalizeCep, normalizeCnpj, normalizeCpf, normalizeCpfCnpj, normalizePhoneBr, normalizeUf, notFoundHandler, onlyDigits, paginationFilterSchema, paginationSchema, parseAcceptLanguage, parseCookies, phoneBrField, refreshSchema, registerExceptionHandlers, requestIdMiddleware, requireRoles, runServer, runWithRequestContext, serverSettingsShape, sessionCookie, setRequestId, signupSchema, sseResponse, statesByRegion, tableNameFor, toDict, toUtc, tokenFromUrl, tokenPairSchema, ufField, updatedByColumn, userPublicSchema, utcnow, verifyOpaqueToken, webPushKeysSchema, webPushPayloadSchema, webPushSubscriptionSchema, wsEnvelopeSchema };
8541
8813
  //# sourceMappingURL=index.js.map
8542
8814
  //# sourceMappingURL=index.js.map