SDK

Полный пример

Пошаговое руководство по созданию полного коннектора с нуля — сервис погодных оповещений с аутентификацией SecretText, одним действием и одним webhook-триггером.

Полный пример: коннектор Weather Alerts

Это пошаговое руководство по созданию полного коннектора для вымышленного Weather Alerts API. Коннектор демонстрирует:

  • Аутентификацию SecretText с валидацией
  • Действие (Action) с несколькими типами свойств, включая Dropdown
  • Webhook-триггер (Trigger) с полным жизненным циклом (onEnable, run, onDisable)

Структура проекта

packages/connectors/weather-alerts/
├── src/
│   ├── index.ts
│   ├── weather-alerts.connector.ts
│   ├── actions/
│   │   └── get-forecast.ts
│   └── triggers/
│       └── severe-alert.ts
└── package.json

Шаг 1: Аутентификация

Определите аутентификацию SecretText с вызовом валидации для проверки API-ключа:

// src/weather-alerts.connector.ts
import {
  createConnector,
  ConnectorAuth,
  ConnectorError,
} from "@triggo/connector-sdk";
import { CONNECTOR_ERROR_CODES } from "@triggo/shared";
import { getForecast } from "./actions/get-forecast.ts";
import { severeAlert } from "./triggers/severe-alert.ts";

const auth = ConnectorAuth.SecretText({
  displayName: "API Key",
  description: "Your Weather Alerts API key from the developer dashboard.",
  validate: async (authValue) => {
    const response = await fetch("https://api.weather-alerts.example.com/v1/me", {
      headers: { "X-Api-Key": authValue.secret },
    });

    if (response.status === 401) {
      throw new ConnectorError(
        CONNECTOR_ERROR_CODES.AUTH_EXPIRED,
        "Invalid API key",
      );
    }

    if (!response.ok) {
      throw new ConnectorError(
        CONNECTOR_ERROR_CODES.UPSTREAM_ERROR,
        `Validation failed: ${response.status}`,
      );
    }
  },
});

export const weatherAlertsConnector = createConnector({
  name: "weather-alerts",
  displayName: "Weather Alerts",
  description: "Get weather forecasts and receive severe weather alerts.",
  auth,
  actions: [getForecast],
  triggers: [severeAlert],
});

Шаг 2: Действие — Get Forecast

Создайте действие, которое получает прогноз погоды для указанного города:

// src/actions/get-forecast.ts
import { createAction, Property, ConnectorError } from "@triggo/connector-sdk";
import { CONNECTOR_ERROR_CODES } from "@triggo/shared";

interface WeatherAuth {
  readonly secret: string;
}

interface ForecastProps {
  readonly city: string;
  readonly units: string;
  readonly days: number;
}

export const getForecast = createAction<WeatherAuth, ForecastProps>({
  name: "get_forecast",
  displayName: "Get Forecast",
  description: "Retrieves a weather forecast for a city.",
  props: {
    city: Property.ShortText({
      displayName: "City",
      description: "City name (e.g., Moscow, Saint Petersburg).",
      required: true,
    }),
    units: Property.Dropdown({
      displayName: "Units",
      description: "Temperature units.",
      required: true,
      defaultValue: "metric",
      options: [
        { label: "Celsius", value: "metric" },
        { label: "Fahrenheit", value: "imperial" },
      ],
    }),
    days: Property.Number({
      displayName: "Forecast Days",
      description: "Number of days to forecast (1-7).",
      required: false,
      defaultValue: 3,
    }),
  },
  errorHandlingOptions: {
    retryOnFailure: { maxRetries: 2, baseIntervalMs: 1000 },
  },
  aiHints:
    "Use this action to get a weather forecast for any city. " +
    "Default is 3 days in Celsius. Supports up to 7 days.",

  async run(context) {
    const { city, units, days } = context.propsValue;
    const apiKey = context.auth.secret;

    const url = new URL("https://api.weather-alerts.example.com/v1/forecast");
    url.searchParams.set("city", city);
    url.searchParams.set("units", units);
    url.searchParams.set("days", String(days));

    const response = await fetch(url.toString(), {
      headers: { "X-Api-Key": apiKey },
    });

    if (response.status === 404) {
      throw new ConnectorError(
        CONNECTOR_ERROR_CODES.NOT_FOUND,
        `City not found: "${city}"`,
      );
    }

    if (response.status === 429) {
      throw new ConnectorError(
        CONNECTOR_ERROR_CODES.RATE_LIMITED,
        "Weather API rate limit exceeded",
      );
    }

    if (!response.ok) {
      throw new ConnectorError(
        CONNECTOR_ERROR_CODES.UPSTREAM_ERROR,
        `Weather API error: ${response.status}`,
      );
    }

    return response.json();
  },
});

Шаг 3: Триггер — Severe Weather Alert

Создайте webhook-триггер, который срабатывает при выпуске предупреждения о суровой погоде:

// src/triggers/severe-alert.ts
import {
  createTrigger,
  TRIGGER_TYPES,
  ConnectorError,
} from "@triggo/connector-sdk";
import { CONNECTOR_ERROR_CODES } from "@triggo/shared";

interface WeatherAuth {
  readonly secret: string;
}

export const severeAlert = createTrigger<WeatherAuth, Record<string, never>>({
  name: "severe_alert",
  displayName: "Severe Weather Alert",
  description: "Triggers when a severe weather alert is issued for any monitored region.",
  props: {},
  type: TRIGGER_TYPES.WEBHOOK,

  outputSchema: {
    type: "object",
    properties: {
      alertId: { type: "string" },
      severity: { type: "string", enum: ["warning", "watch", "emergency"] },
      region: { type: "string" },
      headline: { type: "string" },
      description: { type: "string" },
      issuedAt: { type: "string", format: "date-time" },
    },
    required: ["alertId", "severity", "region", "headline", "issuedAt"],
  },

  sampleData: {
    alertId: "ALERT-2026-001",
    severity: "warning",
    region: "Moscow Oblast",
    headline: "Heavy Snowfall Warning",
    description: "Expected 20-30cm of snow in the next 24 hours.",
    issuedAt: "2026-02-27T08:00:00.000Z",
  },

  aiHints:
    "Use this trigger to react to severe weather alerts. " +
    "Fires automatically when the weather service detects dangerous conditions.",

  async test() {
    return [
      {
        alertId: "ALERT-TEST-001",
        severity: "warning",
        region: "Test Region",
        headline: "Test Alert",
        description: "This is a test alert.",
        issuedAt: new Date().toISOString(),
      },
    ];
  },

  async onEnable(context) {
    const response = await fetch(
      "https://api.weather-alerts.example.com/v1/webhooks",
      {
        method: "POST",
        headers: {
          "X-Api-Key": context.auth.secret,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          url: context.webhookUrl,
          events: ["alert.severe"],
        }),
      },
    );

    if (!response.ok) {
      throw new ConnectorError(
        CONNECTOR_ERROR_CODES.UPSTREAM_ERROR,
        `Failed to register webhook: ${response.status}`,
      );
    }

    const body = (await response.json()) as { id: string };
    await context.store.put("webhookId", body.id);
    return { externalWebhookId: body.id };
  },

  async onDisable(context) {
    const webhookId = (await context.store.get("webhookId")) as string | null;
    if (webhookId) {
      await fetch(
        `https://api.weather-alerts.example.com/v1/webhooks/${webhookId}`,
        {
          method: "DELETE",
          headers: { "X-Api-Key": context.auth.secret },
        },
      );
      await context.store.delete("webhookId");
    }
  },

  async run(context) {
    const payload = context.payload as Record<string, unknown>;
    return [
      {
        alertId: payload["id"],
        severity: payload["severity"],
        region: payload["region"],
        headline: payload["headline"],
        description: payload["description"],
        issuedAt: payload["issued_at"],
      },
    ];
  },
});

Шаг 4: Точка входа

Экспортируйте коннектор из точки входа пакета:

// src/index.ts
export { weatherAlertsConnector } from "./weather-alerts.connector.ts";

Что SDK делает за вас

При вызове createConnector() SDK:

  1. Валидирует все имена (kebab-case для коннектора, snake_case для действий/триггеров)
  2. Генерирует JSON Schema из определений свойств (сохраняется в definition.schema)
  3. Строит карты поиска (actionsMap, triggersMap) для доступа за O(1) движком выполнения
  4. Глубоко замораживает всё определение для предотвращения случайных мутаций во время выполнения

Результирующий ConnectorDefinition готов к регистрации на платформе Triggo и обнаружению AI-генератором пайплайнов.

On this page