Add Activepieces integration for workflow automation
- Add Activepieces fork with SmoothSchedule custom piece - Create integrations app with Activepieces service layer - Add embed token endpoint for iframe integration - Create Automations page with embedded workflow builder - Add sidebar visibility fix for embed mode - Add list inactive customers endpoint to Public API - Include SmoothSchedule triggers: event created/updated/cancelled - Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": ["../../../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
31
activepieces-fork/packages/pieces/community/hedy/README.md
Normal file
31
activepieces-fork/packages/pieces/community/hedy/README.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Hedy Piece for ActivePieces
|
||||
|
||||
AI-powered meeting intelligence integration for ActivePieces.
|
||||
|
||||
## Features
|
||||
- Retrieve meeting sessions, highlights, todos, and topics from Hedy.
|
||||
- Trigger flows when sessions end, highlights are created, or todos are exported.
|
||||
- Support for pagination and Zapier-compatible response formatting.
|
||||
- Optional webhook signature verification for additional security.
|
||||
|
||||
## Authentication
|
||||
1. Sign in to your Hedy dashboard.
|
||||
2. Navigate to **Settings → API**.
|
||||
3. Generate a new API key (it starts with `hedy_live_`).
|
||||
4. Paste the key into the Hedy piece connection in ActivePieces.
|
||||
|
||||
## Example Automations
|
||||
- **Post Session Recaps** – Trigger on `Session Ended` and send meeting notes to Slack, Microsoft Teams, or email.
|
||||
- **Sync Todos** – When a todo is exported from Hedy, automatically create matching tasks in Asana, Todoist, or ClickUp.
|
||||
- **Daily Digest** – Schedule a flow that lists sessions from the last 24 hours, summarises them with AI, and emails the highlights to your team.
|
||||
|
||||
## Error Handling
|
||||
The Hedy piece provides descriptive errors for common issues such as:
|
||||
- Invalid API keys or failed authentication.
|
||||
- Webhook limits being reached (Hedy allows 10 concurrent webhooks per workspace).
|
||||
- Invalid webhook URLs (public HTTPS endpoints are required for production).
|
||||
|
||||
## Support
|
||||
- Hedy API documentation: https://api.hedy.bot/docs
|
||||
- Hedy support: support@hedy.bot
|
||||
- ActivePieces community: https://www.activepieces.com/discord
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "@activepieces/piece-hedy",
|
||||
"version": "0.0.2",
|
||||
"type": "commonjs",
|
||||
"main": "./src/index.js",
|
||||
"types": "./src/index.d.ts",
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"name": "pieces-hedy",
|
||||
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "packages/pieces/community/hedy/src",
|
||||
"projectType": "library",
|
||||
"release": {
|
||||
"version": {
|
||||
"manifestRootsToUpdate": [
|
||||
"dist/{projectRoot}"
|
||||
],
|
||||
"currentVersionResolver": "git-tag",
|
||||
"fallbackCurrentVersionResolver": "disk"
|
||||
}
|
||||
},
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx/js:tsc",
|
||||
"outputs": [
|
||||
"{options.outputPath}"
|
||||
],
|
||||
"options": {
|
||||
"outputPath": "dist/packages/pieces/community/hedy",
|
||||
"tsConfig": "packages/pieces/community/hedy/tsconfig.lib.json",
|
||||
"packageJson": "packages/pieces/community/hedy/package.json",
|
||||
"main": "packages/pieces/community/hedy/src/index.ts",
|
||||
"assets": [
|
||||
"packages/pieces/community/hedy/*.md",
|
||||
{
|
||||
"input": "packages/pieces/community/hedy/src/i18n",
|
||||
"output": "./src/i18n",
|
||||
"glob": "**/!(i18n.json)"
|
||||
}
|
||||
],
|
||||
"buildableProjectDepsInPackageJsonType": "dependencies",
|
||||
"updateBuildableProjectDepsInPackageJson": true
|
||||
},
|
||||
"dependsOn": [
|
||||
"^build",
|
||||
"prebuild"
|
||||
]
|
||||
},
|
||||
"nx-release-publish": {
|
||||
"options": {
|
||||
"packageRoot": "dist/{projectRoot}"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint",
|
||||
"outputs": [
|
||||
"{options.outputFile}"
|
||||
]
|
||||
},
|
||||
"prebuild": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"cwd": "packages/pieces/community/hedy",
|
||||
"command": "bun install --no-save --silent"
|
||||
},
|
||||
"dependsOn": [
|
||||
"^build"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"AI-powered meeting intelligence – be the brightest person in the room.": "AI-gestützte MeetingIntelligenz – sei die hellste Person im Raum.",
|
||||
"Generate an API key from your Hedy dashboard under Settings → API, then paste the key here (it begins with `hedy_live_`).": "Generieren Sie einen API-Schlüssel aus Ihrem Hedy-Dashboard unter Einstellungen → API, fügen Sie dann die Taste hier ein (er beginnt mit `hedy_live_`).",
|
||||
"Get Session": "Sitzung abrufen",
|
||||
"List Sessions": "Sessions auflisten",
|
||||
"Get Highlight": "Hervorheben",
|
||||
"List Highlights": "Markierungen auflisten",
|
||||
"List Todos": "List Todos",
|
||||
"List Session Todos": "Auflistung von Sitzungs-Todos",
|
||||
"Get Topic": "Thema erhalten",
|
||||
"List Topics": "Themen auflisten",
|
||||
"List Topic Sessions": "Themensitzungen auflisten",
|
||||
"Retrieve a specific session by ID.": "Abrufen einer bestimmten Sitzung per ID.",
|
||||
"Retrieve multiple sessions with optional topic filtering and pagination.": "Mehrere Sitzungen mit optionaler Themenfilterung und Seiteninierung abrufen.",
|
||||
"Retrieve a specific highlight by ID.": "Rufen Sie ein spezifisches Highlight per ID ab.",
|
||||
"Retrieve highlights with optional topic filtering and pagination.": "Highlights mit optionaler Themenfilterung und Seiteninierung abrufen.",
|
||||
"Retrieve todos assigned to you in Hedy.": "In Hedy zugewiesene Todos abrufen.",
|
||||
"Retrieve todos generated for a specific session.": "Abrufen von Todos für eine bestimmte Sitzung.",
|
||||
"Retrieve details for a specific topic.": "Ruft Details zu einem bestimmten Thema ab.",
|
||||
"Retrieve all topics from your Hedy workspace.": "Rufen Sie alle Themen aus Ihrem Hedy-Arbeitsbereich ab.",
|
||||
"Retrieve sessions associated with a specific topic.": "Abrufen von Sessionen, die einem bestimmten Thema zugeordnet sind.",
|
||||
"Session ID": "Sitzungs-ID",
|
||||
"Return All": "Alle zurückgeben",
|
||||
"Limit": "Limit",
|
||||
"Response Format": "Antwortformat",
|
||||
"Topic": "Thema",
|
||||
"After Cursor": "Nach Cursor",
|
||||
"Before Cursor": "Vor dem Cursor",
|
||||
"Highlight ID": "ID hervorheben",
|
||||
"Topic ID": "Themen-ID",
|
||||
"The session ID as shown in the Hedy dashboard.": "Die Session-ID wie im Hedy-Dashboard angezeigt.",
|
||||
"Return all results instead of using the limit.": "Gibt alle Ergebnisse anstelle des Limits zurück.",
|
||||
"Maximum number of results to return (default 50).": "Maximale Anzahl der zurückzugebenden Ergebnisse (Standard 50).",
|
||||
"Select the response format to use.": "Wählen Sie das zu verwendende Antwortformat aus.",
|
||||
"Optionally filter results by a specific topic.": "Filtern Sie die Ergebnisse nach einem bestimmten Thema.",
|
||||
"Pagination cursor used to fetch results after a specific item.": "Mit dem Cursor der Pagination werden Ergebnisse nach einem bestimmten Element abgerufen.",
|
||||
"Pagination cursor used to fetch results before a specific item.": "Mit dem Cursor der Pagination werden Ergebnisse vor einem bestimmten Element abgerufen.",
|
||||
"The highlight ID as shown in the Hedy dashboard.": "Die Highlight ID wie im Hedy Dashboard angezeigt.",
|
||||
"The topic ID as shown in the Hedy dashboard.": "Die Themen-ID wie im Hedy-Dashboard angezeigt.",
|
||||
"Standard": "Standard",
|
||||
"Zapier Compatible": "Zapier kompatibel",
|
||||
"Session Created": "Sitzung erstellt",
|
||||
"Session Ended": "Sitzung beendet",
|
||||
"Highlight Created": "Hervorhebung erstellt",
|
||||
"Todo Exported": "Todo exportiert",
|
||||
"Triggers when a new session is created in Hedy.": "Wird ausgelöst, wenn eine neue Sitzung in Hedy erstellt wird.",
|
||||
"Triggers when a session is completed in Hedy.": "Wird ausgelöst, wenn eine Sitzung in Hedy abgeschlossen ist.",
|
||||
"Triggers when a highlight is created during a session.": "Wird ausgelöst, wenn während einer Sitzung ein Highlight erstellt wird.",
|
||||
"Triggers when a todo item is exported from Hedy.": "Wird ausgelöst, wenn ein Todo-Item von Hedy exportiert wird.",
|
||||
"Verify Signature": "Signatur überprüfen",
|
||||
"Verify the webhook signature using the secret returned by Hedy. Disable this option if Hedy does not provide a signing secret for your account.": "Verifizieren Sie die Webhook-Signatur mit dem von Hedy zurückgegebenen Geheimnis. Deaktivieren Sie diese Option, wenn Hedy kein Geheimnis für Ihre Anmeldung zur Verfügung stellt."
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"AI-powered meeting intelligence – be the brightest person in the room.": "La inteligencia de reuniones de la AI: sea la persona más brillante de la sala.",
|
||||
"Generate an API key from your Hedy dashboard under Settings → API, then paste the key here (it begins with `hedy_live_`).": "Genera una clave API desde su panel de control de Hedy en Configuración → API, luego pegue la clave aquí (comienza con `hedy_live_`).",
|
||||
"Get Session": "Obtener sesión",
|
||||
"List Sessions": "Listar Sesiones",
|
||||
"Get Highlight": "Resaltar",
|
||||
"List Highlights": "Lista de destacados",
|
||||
"List Todos": "List Todos",
|
||||
"List Session Todos": "Listar Todos de Sesiones",
|
||||
"Get Topic": "Obtener Tema",
|
||||
"List Topics": "Temas de lista",
|
||||
"List Topic Sessions": "Listar sesiones de temas",
|
||||
"Retrieve a specific session by ID.": "Recuperar una sesión específica por ID.",
|
||||
"Retrieve multiple sessions with optional topic filtering and pagination.": "Recuperar múltiples sesiones con filtrado opcional de temas y paginación.",
|
||||
"Retrieve a specific highlight by ID.": "Recuperar un resaltado específico por ID.",
|
||||
"Retrieve highlights with optional topic filtering and pagination.": "Recuperar resaltados con filtrado opcional de temas y paginación.",
|
||||
"Retrieve todos assigned to you in Hedy.": "Recuperar tareas asignadas en Hedy.",
|
||||
"Retrieve todos generated for a specific session.": "Recuperar todo generado para una sesión específica.",
|
||||
"Retrieve details for a specific topic.": "Recuperar detalles de un tema específico.",
|
||||
"Retrieve all topics from your Hedy workspace.": "Recuperar todos los temas de su espacio de trabajo Hedy.",
|
||||
"Retrieve sessions associated with a specific topic.": "Recuperar sesiones asociadas con un tema específico.",
|
||||
"Session ID": "ID de sesión",
|
||||
"Return All": "Devolver todos",
|
||||
"Limit": "Límite",
|
||||
"Response Format": "Formato de respuesta",
|
||||
"Topic": "Tema",
|
||||
"After Cursor": "Después del cursor",
|
||||
"Before Cursor": "Antes del Cursor",
|
||||
"Highlight ID": "Resaltar ID",
|
||||
"Topic ID": "ID del tema",
|
||||
"The session ID as shown in the Hedy dashboard.": "El ID de sesión como se muestra en el panel de control de Hedy.",
|
||||
"Return all results instead of using the limit.": "Devuelve todos los resultados en lugar de usar el límite.",
|
||||
"Maximum number of results to return (default 50).": "Número máximo de resultados a devolver (por defecto 50).",
|
||||
"Select the response format to use.": "Seleccione el formato de respuesta a utilizar.",
|
||||
"Optionally filter results by a specific topic.": "Opcionalmente filtrar resultados por un tema específico.",
|
||||
"Pagination cursor used to fetch results after a specific item.": "cursor de paginación usado para obtener resultados después de un elemento específico.",
|
||||
"Pagination cursor used to fetch results before a specific item.": "cursor de paginación usado para obtener resultados antes de un elemento específico.",
|
||||
"The highlight ID as shown in the Hedy dashboard.": "El ID de resaltado como se muestra en el panel de control de Hedy.",
|
||||
"The topic ID as shown in the Hedy dashboard.": "El ID del tema como se muestra en el panel de control de Hedy.",
|
||||
"Standard": "Estándar",
|
||||
"Zapier Compatible": "Compatible con Zapier",
|
||||
"Session Created": "Sesión creada",
|
||||
"Session Ended": "Sesión finalizada",
|
||||
"Highlight Created": "Resaltar creado",
|
||||
"Todo Exported": "Tarea exportada",
|
||||
"Triggers when a new session is created in Hedy.": "Se activa cuando se crea una nueva sesión en Hedy.",
|
||||
"Triggers when a session is completed in Hedy.": "Dispara cuando una sesión se completa en Hedy.",
|
||||
"Triggers when a highlight is created during a session.": "Dispara cuando se crea un resaltado durante una sesión.",
|
||||
"Triggers when a todo item is exported from Hedy.": "Dispara cuando un elemento de tarea es exportado desde Hedy.",
|
||||
"Verify Signature": "Verificar Firma",
|
||||
"Verify the webhook signature using the secret returned by Hedy. Disable this option if Hedy does not provide a signing secret for your account.": "Verifique la firma del webhook usando el secreto devuelto por Hedy. Deshabilite esta opción si Hedy no proporciona un secreto de firma para su cuenta."
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"AI-powered meeting intelligence – be the brightest person in the room.": "L’intelligence de réunion de l’IA – soyez la personne la plus brillante dans la salle.",
|
||||
"Generate an API key from your Hedy dashboard under Settings → API, then paste the key here (it begins with `hedy_live_`).": "Générez une clé API à partir de votre tableau de bord Hedy sous Paramètres → API, puis collez la clé ici (elle commence par `hedy_live_`).",
|
||||
"Get Session": "Obtenir une session",
|
||||
"List Sessions": "Lister les sessions",
|
||||
"Get Highlight": "Obtenir la surbrillance",
|
||||
"List Highlights": "Liste des points forts",
|
||||
"List Todos": "List Todos",
|
||||
"List Session Todos": "Liste des todos de session",
|
||||
"Get Topic": "Obtenir le sujet",
|
||||
"List Topics": "Liste des sujets",
|
||||
"List Topic Sessions": "Lister les sessions de sujet",
|
||||
"Retrieve a specific session by ID.": "Récupérer une session spécifique par ID.",
|
||||
"Retrieve multiple sessions with optional topic filtering and pagination.": "Récupère plusieurs sessions avec filtrage et pagination facultatifs des sujets.",
|
||||
"Retrieve a specific highlight by ID.": "Récupérer une surbrillance spécifique par ID.",
|
||||
"Retrieve highlights with optional topic filtering and pagination.": "Récupérer les surlignements avec filtrage facultatif des sujets et de la pagination.",
|
||||
"Retrieve todos assigned to you in Hedy.": "Récupérez les todos qui vous sont assignées à Hedy.",
|
||||
"Retrieve todos generated for a specific session.": "Récupérer les todos générées pour une session spécifique.",
|
||||
"Retrieve details for a specific topic.": "Récupérer les détails d'un sujet spécifique.",
|
||||
"Retrieve all topics from your Hedy workspace.": "Récupérer tous les sujets de votre espace de travail Hedy",
|
||||
"Retrieve sessions associated with a specific topic.": "Récupérer les sessions associées à un sujet spécifique.",
|
||||
"Session ID": "ID de session",
|
||||
"Return All": "Retourner tout",
|
||||
"Limit": "Limite",
|
||||
"Response Format": "Format de réponse",
|
||||
"Topic": "Sujet",
|
||||
"After Cursor": "Après le curseur",
|
||||
"Before Cursor": "Avant le curseur",
|
||||
"Highlight ID": "Identifiant de surbrillance",
|
||||
"Topic ID": "ID du sujet",
|
||||
"The session ID as shown in the Hedy dashboard.": "L'ID de la session comme indiqué dans le tableau de bord Hedy",
|
||||
"Return all results instead of using the limit.": "Renvoie tous les résultats au lieu d'utiliser la limite.",
|
||||
"Maximum number of results to return (default 50).": "Nombre maximum de résultats à retourner (par défaut 50).",
|
||||
"Select the response format to use.": "Sélectionnez le format de réponse à utiliser.",
|
||||
"Optionally filter results by a specific topic.": "Filtrer éventuellement les résultats par sujet spécifique.",
|
||||
"Pagination cursor used to fetch results after a specific item.": "Curseur de pagination utilisé pour récupérer les résultats après un élément spécifique.",
|
||||
"Pagination cursor used to fetch results before a specific item.": "Curseur de pagination utilisé pour récupérer les résultats avant un élément spécifique.",
|
||||
"The highlight ID as shown in the Hedy dashboard.": "L'ID de surbrillance comme indiqué dans le tableau de bord Hedy",
|
||||
"The topic ID as shown in the Hedy dashboard.": "L'ID du sujet tel qu'indiqué dans le tableau de bord Hedy",
|
||||
"Standard": "Standard",
|
||||
"Zapier Compatible": "Compatible avec Zapier",
|
||||
"Session Created": "Session créée",
|
||||
"Session Ended": "Session terminée",
|
||||
"Highlight Created": "Surlignage créé",
|
||||
"Todo Exported": "Todo exportée",
|
||||
"Triggers when a new session is created in Hedy.": "Déclenche quand une nouvelle session est créée dans Hedy.",
|
||||
"Triggers when a session is completed in Hedy.": "Déclenche quand une session est terminée à Hedy.",
|
||||
"Triggers when a highlight is created during a session.": "Déclenche quand une surbrillance est créée pendant une session.",
|
||||
"Triggers when a todo item is exported from Hedy.": "Déclenche lorsqu'un élément de todo est exporté de Hedy.",
|
||||
"Verify Signature": "Vérifier la signature",
|
||||
"Verify the webhook signature using the secret returned by Hedy. Disable this option if Hedy does not provide a signing secret for your account.": "Vérifiez la signature du webhook en utilisant le secret retourné par Hedy. Désactivez cette option si Hedy ne fournit pas de secret de signature pour votre compte."
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"AI-powered meeting intelligence – be the brightest person in the room.": "AIを活用した会議インテリジェンスは、部屋の中で最も明るい人になります。",
|
||||
"Generate an API key from your Hedy dashboard under Settings → API, then paste the key here (it begins with `hedy_live_`).": "Hedy ダッシュボードから API キーを生成するには、設定 → API を選択し、ここにキーを貼り付けます (`hedy_live_`で始まります)。",
|
||||
"Get Session": "セッションを取得",
|
||||
"List Sessions": "セッション一覧",
|
||||
"Get Highlight": "ハイライトを取得",
|
||||
"List Highlights": "リストのハイライト",
|
||||
"List Todos": "List Todos",
|
||||
"List Session Todos": "セッションのタスク一覧",
|
||||
"Get Topic": "トピックを取得",
|
||||
"List Topics": "トピック一覧",
|
||||
"List Topic Sessions": "トピックセッションの一覧",
|
||||
"Retrieve a specific session by ID.": "IDで特定のセッションを取得します。",
|
||||
"Retrieve multiple sessions with optional topic filtering and pagination.": "オプションのトピックフィルタリングとページネーションで複数のセッションを取得します。",
|
||||
"Retrieve a specific highlight by ID.": "ID による特定のハイライトを取得します。",
|
||||
"Retrieve highlights with optional topic filtering and pagination.": "オプションのトピックフィルタリングとページネーションでハイライトを取得します。",
|
||||
"Retrieve todos assigned to you in Hedy.": "ヘディであなたに割り当てられたタスクを取得します。",
|
||||
"Retrieve todos generated for a specific session.": "特定のセッションで生成されたタスクを取得します。",
|
||||
"Retrieve details for a specific topic.": "特定のトピックの詳細を取得します。",
|
||||
"Retrieve all topics from your Hedy workspace.": "Hedy ワークスペースからすべてのトピックを取得します。",
|
||||
"Retrieve sessions associated with a specific topic.": "特定のトピックに関連付けられているセッションを取得します。",
|
||||
"Session ID": "セッションID",
|
||||
"Return All": "すべて戻る",
|
||||
"Limit": "制限",
|
||||
"Response Format": "応答形式",
|
||||
"Topic": "トピック",
|
||||
"After Cursor": "カーソルの後",
|
||||
"Before Cursor": "カーソルの前",
|
||||
"Highlight ID": "IDを強調表示",
|
||||
"Topic ID": "トピックID",
|
||||
"The session ID as shown in the Hedy dashboard.": "Hedyダッシュボードに表示されるセッションID。",
|
||||
"Return all results instead of using the limit.": "制限を使用せずにすべての結果を返します。",
|
||||
"Maximum number of results to return (default 50).": "返す結果の最大数(デフォルトは50)。",
|
||||
"Select the response format to use.": "使用する応答形式を選択します。",
|
||||
"Optionally filter results by a specific topic.": "オプションで特定のトピックで結果をフィルタリングします。",
|
||||
"Pagination cursor used to fetch results after a specific item.": "特定のアイテムの後に結果を取得するために使用されるページネーションカーソル。",
|
||||
"Pagination cursor used to fetch results before a specific item.": "特定のアイテムの前に結果を取得するために使用されるページネーションカーソル。",
|
||||
"The highlight ID as shown in the Hedy dashboard.": "Hedyダッシュボードに表示されるハイライトID。",
|
||||
"The topic ID as shown in the Hedy dashboard.": "Hedy ダッシュボードに表示されるトピック ID 。",
|
||||
"Standard": "標準",
|
||||
"Zapier Compatible": "Zapier 互換性あり",
|
||||
"Session Created": "セッションが作成されました",
|
||||
"Session Ended": "セッション終了",
|
||||
"Highlight Created": "作成されたハイライト",
|
||||
"Todo Exported": "Todo がエクスポートされました",
|
||||
"Triggers when a new session is created in Hedy.": "Hedy で新しいセッションが作成されたときにトリガーします。",
|
||||
"Triggers when a session is completed in Hedy.": "Hedy でセッションが完了したときにトリガーします。",
|
||||
"Triggers when a highlight is created during a session.": "セッション中にハイライトが作成されたときにトリガーされます。",
|
||||
"Triggers when a todo item is exported from Hedy.": "Hedy からタスクアイテムをエクスポートしたときにトリガーします。",
|
||||
"Verify Signature": "署名の確認",
|
||||
"Verify the webhook signature using the secret returned by Hedy. Disable this option if Hedy does not provide a signing secret for your account.": "Hedy が返却したシークレットを使用して Webhook の署名を確認します。Hedy があなたのアカウントの署名の秘密を提供していない場合は、このオプションを無効にします。"
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"AI-powered meeting intelligence – be the brightest person in the room.": "AI-aangedreven meetingintelligentie – wees de mooiste persoon in de kamer.",
|
||||
"Generate an API key from your Hedy dashboard under Settings → API, then paste the key here (it begins with `hedy_live_`).": "Genereer een API-sleutel van uw Hedy dashboard onder Instellingen → API, plak vervolgens de sleutel hier (het begint met `hedy_live_`).",
|
||||
"Get Session": "Sessie opvragen",
|
||||
"List Sessions": "Lijst van sessies",
|
||||
"Get Highlight": "Krijg accentuering",
|
||||
"List Highlights": "Lijst accentueringen",
|
||||
"List Todos": "List Todos",
|
||||
"List Session Todos": "Sessie totaal weergeven",
|
||||
"Get Topic": "Topic opvragen",
|
||||
"List Topics": "Onderwerpen weergeven",
|
||||
"List Topic Sessions": "Lijst van onderwerpsessies",
|
||||
"Retrieve a specific session by ID.": "Ophalen van een specifieke sessie met ID.",
|
||||
"Retrieve multiple sessions with optional topic filtering and pagination.": "Haal meerdere sessies op met optionele topic filtering en paginering.",
|
||||
"Retrieve a specific highlight by ID.": "Ophalen van een specifieke markering door ID.",
|
||||
"Retrieve highlights with optional topic filtering and pagination.": "Ophalen hoogtepunten met optionele topic filtering en paginering.",
|
||||
"Retrieve todos assigned to you in Hedy.": "Ophalen van alle aan u toegewezen taken in Hedy.",
|
||||
"Retrieve todos generated for a specific session.": "Ophalen todos gegenereerd voor een specifieke sessie.",
|
||||
"Retrieve details for a specific topic.": "Haal details op voor een specifiek onderwerp.",
|
||||
"Retrieve all topics from your Hedy workspace.": "Haal alle onderwerpen op van je Hedy workspace.",
|
||||
"Retrieve sessions associated with a specific topic.": "Ophalen van sessies die gekoppeld zijn aan een specifiek onderwerp.",
|
||||
"Session ID": "Sessie ID",
|
||||
"Return All": "Retourneer alles",
|
||||
"Limit": "Limiet",
|
||||
"Response Format": "Antwoord formaat",
|
||||
"Topic": "Onderwerp",
|
||||
"After Cursor": "Na cursor",
|
||||
"Before Cursor": "Voor cursor",
|
||||
"Highlight ID": "ID markeren",
|
||||
"Topic ID": "Onderwerp ID",
|
||||
"The session ID as shown in the Hedy dashboard.": "De sessie-ID zoals weergegeven in het Hedy dashboard.",
|
||||
"Return all results instead of using the limit.": "Resultaat is alle resultaten in plaats van het gebruik van de limiet.",
|
||||
"Maximum number of results to return (default 50).": "Maximum aantal resultaten om terug te keren (standaard 50).",
|
||||
"Select the response format to use.": "Selecteer het antwoordformaat om te gebruiken.",
|
||||
"Optionally filter results by a specific topic.": "Filter de resultaten optioneel op een specifiek onderwerp.",
|
||||
"Pagination cursor used to fetch results after a specific item.": "Paginering cursor wordt gebruikt om resultaten op te halen na een specifiek item.",
|
||||
"Pagination cursor used to fetch results before a specific item.": "Paginering cursor wordt gebruikt om resultaten op te halen voor een specifiek item.",
|
||||
"The highlight ID as shown in the Hedy dashboard.": "De markeerstitel-ID zoals getoond in het Hedy dashboard.",
|
||||
"The topic ID as shown in the Hedy dashboard.": "Het onderwerp ID zoals getoond in het Hedy dashboard.",
|
||||
"Standard": "Standaard",
|
||||
"Zapier Compatible": "Zapier Compatibel",
|
||||
"Session Created": "Sessie aangemaakt",
|
||||
"Session Ended": "Sessie beëindigd",
|
||||
"Highlight Created": "Markeer Aangemaakt",
|
||||
"Todo Exported": "Todo geëxporteerd",
|
||||
"Triggers when a new session is created in Hedy.": "Triggert wanneer een nieuwe sessie wordt gemaakt in Hedy.",
|
||||
"Triggers when a session is completed in Hedy.": "Triggert wanneer een sessie is voltooid in Hedy.",
|
||||
"Triggers when a highlight is created during a session.": "Triggert wanneer een markering wordt gemaakt tijdens een sessie.",
|
||||
"Triggers when a todo item is exported from Hedy.": "Triggert wanneer een todo-item wordt geëxporteerd vanuit Hedy.",
|
||||
"Verify Signature": "Verifieer handtekening",
|
||||
"Verify the webhook signature using the secret returned by Hedy. Disable this option if Hedy does not provide a signing secret for your account.": "Verifieer de webhook handtekening met behulp van het door Hedy geretourneerde geheim. Schakel deze optie uit als Hedy geen handtekening voor uw account inlevert."
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"AI-powered meeting intelligence – be the brightest person in the room.": "Inteligência de reunião com o poder IA — seja a pessoa mais brilhante na sala.",
|
||||
"Generate an API key from your Hedy dashboard under Settings → API, then paste the key here (it begins with `hedy_live_`).": "Gerar uma chave de API a partir do seu painel Hedy em Configurações → API, e então cole a chave aqui (ele começa com `hedy_live_`).",
|
||||
"Get Session": "Obter a sessão",
|
||||
"List Sessions": "Listar Sessões",
|
||||
"Get Highlight": "Obter Destaque",
|
||||
"List Highlights": "Listar destaques",
|
||||
"List Todos": "List Todos",
|
||||
"List Session Todos": "Listar todas as sessões",
|
||||
"Get Topic": "Obter Tópico",
|
||||
"List Topics": "Listar tópicos",
|
||||
"List Topic Sessions": "Listar sessões de tópicos",
|
||||
"Retrieve a specific session by ID.": "Recuperar uma sessão específica por ID.",
|
||||
"Retrieve multiple sessions with optional topic filtering and pagination.": "Recuperar várias sessões com filtragem e paginação de tópico opcionais.",
|
||||
"Retrieve a specific highlight by ID.": "Recuperar um destaque específico por ID.",
|
||||
"Retrieve highlights with optional topic filtering and pagination.": "Recuperar destaques com filtragem e paginação de tópico opcionais.",
|
||||
"Retrieve todos assigned to you in Hedy.": "Recupere tarefas atribuídas a você em Hedy.",
|
||||
"Retrieve todos generated for a specific session.": "Recuperar tarefas geradas para uma sessão específica.",
|
||||
"Retrieve details for a specific topic.": "Recuperar detalhes para um tópico específico.",
|
||||
"Retrieve all topics from your Hedy workspace.": "Recupere todos os tópicos da sua área de trabalho Hedy.",
|
||||
"Retrieve sessions associated with a specific topic.": "Recuperar sessões associadas a um tópico específico.",
|
||||
"Session ID": "ID da sessão",
|
||||
"Return All": "Devolver tudo",
|
||||
"Limit": "Limitar",
|
||||
"Response Format": "Formato de Resposta",
|
||||
"Topic": "Tópico",
|
||||
"After Cursor": "Após Cursor",
|
||||
"Before Cursor": "Antes do Cursor",
|
||||
"Highlight ID": "Destacar ID",
|
||||
"Topic ID": "ID do tópico",
|
||||
"The session ID as shown in the Hedy dashboard.": "O ID de sessão como mostrado no painel Hedy.",
|
||||
"Return all results instead of using the limit.": "Retornar todos os resultados em vez de usar o limite.",
|
||||
"Maximum number of results to return (default 50).": "Número máximo de resultados a retornar (padrão 50).",
|
||||
"Select the response format to use.": "Selecione o formato de resposta a ser usado.",
|
||||
"Optionally filter results by a specific topic.": "Opcionalmente filtra os resultados por um tópico específico.",
|
||||
"Pagination cursor used to fetch results after a specific item.": "Cursor de paginação usado para obter resultados após um item específico.",
|
||||
"Pagination cursor used to fetch results before a specific item.": "Cursor de paginação usado para obter resultados antes de um item específico.",
|
||||
"The highlight ID as shown in the Hedy dashboard.": "O ID de destaque como mostrado no painel Hedy.",
|
||||
"The topic ID as shown in the Hedy dashboard.": "O ID do tópico como mostrado no painel Hedy.",
|
||||
"Standard": "Padrão",
|
||||
"Zapier Compatible": "Compatível com Zapier",
|
||||
"Session Created": "Sessão Criada",
|
||||
"Session Ended": "Sessão Encerrada",
|
||||
"Highlight Created": "Destacar Criado",
|
||||
"Todo Exported": "Tarefa exportada",
|
||||
"Triggers when a new session is created in Hedy.": "Aciona quando uma sessão é criada no Hedy.",
|
||||
"Triggers when a session is completed in Hedy.": "Dispara quando uma sessão for concluída no Hedy.",
|
||||
"Triggers when a highlight is created during a session.": "Dispara quando um destaque é criado durante uma sessão.",
|
||||
"Triggers when a todo item is exported from Hedy.": "Aciona quando um item de tarefa é exportado do Hedy.",
|
||||
"Verify Signature": "Verificar assinatura",
|
||||
"Verify the webhook signature using the secret returned by Hedy. Disable this option if Hedy does not provide a signing secret for your account.": "Verifique a assinatura de webhook usando o segredo retornado pelo Hedy. Desative essa opção se Hedy não fornecer um segredo de assinatura para sua conta."
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"AI-powered meeting intelligence – be the brightest person in the room.": "AI-powered meeting intelligence – be the brightest person in the room.",
|
||||
"Generate an API key from your Hedy dashboard under Settings → API, then paste the key here (it begins with `hedy_live_`).": "Generate an API key from your Hedy dashboard under Settings → API, then paste the key here (it begins with `hedy_live_`).",
|
||||
"Get Session": "Get Session",
|
||||
"List Sessions": "List Sessions",
|
||||
"Get Highlight": "Get Highlight",
|
||||
"List Highlights": "List Highlights",
|
||||
"List Todos": "List Todos",
|
||||
"List Session Todos": "List Session Todos",
|
||||
"Get Topic": "Get Topic",
|
||||
"List Topics": "List Topics",
|
||||
"List Topic Sessions": "List Topic Sessions",
|
||||
"Retrieve a specific session by ID.": "Retrieve a specific session by ID.",
|
||||
"Retrieve multiple sessions with optional topic filtering and pagination.": "Retrieve multiple sessions with optional topic filtering and pagination.",
|
||||
"Retrieve a specific highlight by ID.": "Retrieve a specific highlight by ID.",
|
||||
"Retrieve highlights with optional topic filtering and pagination.": "Retrieve highlights with optional topic filtering and pagination.",
|
||||
"Retrieve todos assigned to you in Hedy.": "Retrieve todos assigned to you in Hedy.",
|
||||
"Retrieve todos generated for a specific session.": "Retrieve todos generated for a specific session.",
|
||||
"Retrieve details for a specific topic.": "Retrieve details for a specific topic.",
|
||||
"Retrieve all topics from your Hedy workspace.": "Retrieve all topics from your Hedy workspace.",
|
||||
"Retrieve sessions associated with a specific topic.": "Retrieve sessions associated with a specific topic.",
|
||||
"Session ID": "Session ID",
|
||||
"Return All": "Return All",
|
||||
"Limit": "Limit",
|
||||
"Response Format": "Response Format",
|
||||
"Topic": "Topic",
|
||||
"After Cursor": "After Cursor",
|
||||
"Before Cursor": "Before Cursor",
|
||||
"Highlight ID": "Highlight ID",
|
||||
"Topic ID": "Topic ID",
|
||||
"The session ID as shown in the Hedy dashboard.": "The session ID as shown in the Hedy dashboard.",
|
||||
"Return all results instead of using the limit.": "Return all results instead of using the limit.",
|
||||
"Maximum number of results to return (default 50).": "Maximum number of results to return (default 50).",
|
||||
"Select the response format to use.": "Select the response format to use.",
|
||||
"Optionally filter results by a specific topic.": "Optionally filter results by a specific topic.",
|
||||
"Pagination cursor used to fetch results after a specific item.": "Pagination cursor used to fetch results after a specific item.",
|
||||
"Pagination cursor used to fetch results before a specific item.": "Pagination cursor used to fetch results before a specific item.",
|
||||
"The highlight ID as shown in the Hedy dashboard.": "The highlight ID as shown in the Hedy dashboard.",
|
||||
"The topic ID as shown in the Hedy dashboard.": "The topic ID as shown in the Hedy dashboard.",
|
||||
"Standard": "Standard",
|
||||
"Zapier Compatible": "Zapier Compatible",
|
||||
"Session Created": "Session Created",
|
||||
"Session Ended": "Session Ended",
|
||||
"Highlight Created": "Highlight Created",
|
||||
"Todo Exported": "Todo Exported",
|
||||
"Triggers when a new session is created in Hedy.": "Triggers when a new session is created in Hedy.",
|
||||
"Triggers when a session is completed in Hedy.": "Triggers when a session is completed in Hedy.",
|
||||
"Triggers when a highlight is created during a session.": "Triggers when a highlight is created during a session.",
|
||||
"Triggers when a todo item is exported from Hedy.": "Triggers when a todo item is exported from Hedy.",
|
||||
"Verify Signature": "Verify Signature",
|
||||
"Verify the webhook signature using the secret returned by Hedy. Disable this option if Hedy does not provide a signing secret for your account.": "Verify the webhook signature using the secret returned by Hedy. Disable this option if Hedy does not provide a signing secret for your account."
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"AI-powered meeting intelligence – be the brightest person in the room.": "AI-powered meeting intelligence – be the brightest person in the room.",
|
||||
"Generate an API key from your Hedy dashboard under Settings → API, then paste the key here (it begins with `hedy_live_`).": "Generate an API key from your Hedy dashboard under Settings → API, then paste the key here (it begins with `hedy_live_`).",
|
||||
"Get Session": "Get Session",
|
||||
"List Sessions": "List Sessions",
|
||||
"Get Highlight": "Get Highlight",
|
||||
"List Highlights": "List Highlights",
|
||||
"List Todos": "List Todos",
|
||||
"List Session Todos": "List Session Todos",
|
||||
"Get Topic": "Get Topic",
|
||||
"List Topics": "List Topics",
|
||||
"List Topic Sessions": "List Topic Sessions",
|
||||
"Retrieve a specific session by ID.": "Retrieve a specific session by ID.",
|
||||
"Retrieve multiple sessions with optional topic filtering and pagination.": "Retrieve multiple sessions with optional topic filtering and pagination.",
|
||||
"Retrieve a specific highlight by ID.": "Retrieve a specific highlight by ID.",
|
||||
"Retrieve highlights with optional topic filtering and pagination.": "Retrieve highlights with optional topic filtering and pagination.",
|
||||
"Retrieve todos assigned to you in Hedy.": "Retrieve todos assigned to you in Hedy.",
|
||||
"Retrieve todos generated for a specific session.": "Retrieve todos generated for a specific session.",
|
||||
"Retrieve details for a specific topic.": "Retrieve details for a specific topic.",
|
||||
"Retrieve all topics from your Hedy workspace.": "Retrieve all topics from your Hedy workspace.",
|
||||
"Retrieve sessions associated with a specific topic.": "Retrieve sessions associated with a specific topic.",
|
||||
"Session ID": "Session ID",
|
||||
"Return All": "Return All",
|
||||
"Limit": "Limit",
|
||||
"Response Format": "Response Format",
|
||||
"Topic": "Topic",
|
||||
"After Cursor": "After Cursor",
|
||||
"Before Cursor": "Before Cursor",
|
||||
"Highlight ID": "Highlight ID",
|
||||
"Topic ID": "Topic ID",
|
||||
"The session ID as shown in the Hedy dashboard.": "The session ID as shown in the Hedy dashboard.",
|
||||
"Return all results instead of using the limit.": "Return all results instead of using the limit.",
|
||||
"Maximum number of results to return (default 50).": "Maximum number of results to return (default 50).",
|
||||
"Select the response format to use.": "Select the response format to use.",
|
||||
"Optionally filter results by a specific topic.": "Optionally filter results by a specific topic.",
|
||||
"Pagination cursor used to fetch results after a specific item.": "Pagination cursor used to fetch results after a specific item.",
|
||||
"Pagination cursor used to fetch results before a specific item.": "Pagination cursor used to fetch results before a specific item.",
|
||||
"The highlight ID as shown in the Hedy dashboard.": "The highlight ID as shown in the Hedy dashboard.",
|
||||
"The topic ID as shown in the Hedy dashboard.": "The topic ID as shown in the Hedy dashboard.",
|
||||
"Standard": "Standard",
|
||||
"Zapier Compatible": "Zapier Compatible",
|
||||
"Session Created": "Session Created",
|
||||
"Session Ended": "Session Ended",
|
||||
"Highlight Created": "Highlight Created",
|
||||
"Todo Exported": "Todo Exported",
|
||||
"Triggers when a new session is created in Hedy.": "Triggers when a new session is created in Hedy.",
|
||||
"Triggers when a session is completed in Hedy.": "Triggers when a session is completed in Hedy.",
|
||||
"Triggers when a highlight is created during a session.": "Triggers when a highlight is created during a session.",
|
||||
"Triggers when a todo item is exported from Hedy.": "Triggers when a todo item is exported from Hedy.",
|
||||
"Verify Signature": "Verify Signature",
|
||||
"Verify the webhook signature using the secret returned by Hedy. Disable this option if Hedy does not provide a signing secret for your account.": "Verify the webhook signature using the secret returned by Hedy. Disable this option if Hedy does not provide a signing secret for your account."
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { createPiece } from '@activepieces/pieces-framework';
|
||||
import { PieceCategory } from '@activepieces/shared';
|
||||
import { hedyAuth } from './lib/auth';
|
||||
import {
|
||||
getSession,
|
||||
listSessions,
|
||||
getHighlight,
|
||||
listHighlights,
|
||||
listTodos,
|
||||
listSessionTodos,
|
||||
getTopic,
|
||||
listTopics,
|
||||
listTopicSessions,
|
||||
} from './lib/actions';
|
||||
import {
|
||||
sessionCreated,
|
||||
sessionEnded,
|
||||
highlightCreated,
|
||||
todoExported,
|
||||
} from './lib/triggers';
|
||||
|
||||
export const hedy = createPiece({
|
||||
displayName: 'Hedy',
|
||||
description: 'AI-powered meeting intelligence – be the brightest person in the room.',
|
||||
auth: hedyAuth,
|
||||
minimumSupportedRelease: '0.69.0',
|
||||
logoUrl: 'https://cdn.activepieces.com/pieces/hedy.png',
|
||||
categories: [PieceCategory.PRODUCTIVITY, PieceCategory.ARTIFICIAL_INTELLIGENCE],
|
||||
authors: ['HedyAI'],
|
||||
actions: [
|
||||
getSession,
|
||||
listSessions,
|
||||
getHighlight,
|
||||
listHighlights,
|
||||
listTodos,
|
||||
listSessionTodos,
|
||||
getTopic,
|
||||
listTopics,
|
||||
listTopicSessions,
|
||||
],
|
||||
triggers: [sessionCreated, sessionEnded, highlightCreated, todoExported],
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { hedyAuth } from '../../auth';
|
||||
import { HedyApiClient, unwrapResource } from '../../common/client';
|
||||
import { commonProps } from '../../common/props';
|
||||
import { Highlight } from '../../common/types';
|
||||
|
||||
export const getHighlight = createAction({
|
||||
auth: hedyAuth,
|
||||
name: 'get-highlight',
|
||||
displayName: 'Get Highlight',
|
||||
description: 'Retrieve a specific highlight by ID.',
|
||||
props: {
|
||||
highlightId: commonProps.highlightId,
|
||||
},
|
||||
async run(context) {
|
||||
const highlightId = context.propsValue.highlightId as string;
|
||||
const client = new HedyApiClient(context.auth.secret_text);
|
||||
const response = await client.request<Highlight>({
|
||||
method: HttpMethod.GET,
|
||||
path: `/highlights/${highlightId}`,
|
||||
});
|
||||
|
||||
return unwrapResource(response);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './get-highlight';
|
||||
export * from './list-highlights';
|
||||
@@ -0,0 +1,42 @@
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { hedyAuth } from '../../auth';
|
||||
import { HedyApiClient } from '../../common/client';
|
||||
import { commonProps } from '../../common/props';
|
||||
import { topicDropdown } from '../../common/load-options';
|
||||
import { Highlight } from '../../common/types';
|
||||
import { assertLimit } from '../../common/validation';
|
||||
|
||||
export const listHighlights = createAction({
|
||||
auth: hedyAuth,
|
||||
name: 'list-highlights',
|
||||
displayName: 'List Highlights',
|
||||
description: 'Retrieve highlights with optional topic filtering and pagination.',
|
||||
props: {
|
||||
returnAll: commonProps.returnAll,
|
||||
limit: commonProps.limit,
|
||||
format: commonProps.format,
|
||||
topicId: topicDropdown,
|
||||
after: commonProps.afterCursor,
|
||||
before: commonProps.beforeCursor,
|
||||
},
|
||||
async run(context) {
|
||||
const client = new HedyApiClient(context.auth.secret_text);
|
||||
const { returnAll, limit, format, topicId, after, before } = context.propsValue as {
|
||||
returnAll?: boolean;
|
||||
limit?: number;
|
||||
format?: 'standard' | 'zapier';
|
||||
topicId?: string;
|
||||
after?: string;
|
||||
before?: string;
|
||||
};
|
||||
|
||||
return client.paginate<Highlight>('/highlights', {
|
||||
returnAll: Boolean(returnAll),
|
||||
limit: assertLimit(limit),
|
||||
format,
|
||||
topicId,
|
||||
after,
|
||||
before,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from './sessions';
|
||||
export * from './highlights';
|
||||
export * from './todos';
|
||||
export * from './topics';
|
||||
@@ -0,0 +1,26 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { hedyAuth } from '../../auth';
|
||||
import { HedyApiClient, unwrapResource } from '../../common/client';
|
||||
import { commonProps } from '../../common/props';
|
||||
import { Session } from '../../common/types';
|
||||
|
||||
export const getSession = createAction({
|
||||
auth: hedyAuth,
|
||||
name: 'get-session',
|
||||
displayName: 'Get Session',
|
||||
description: 'Retrieve a specific session by ID.',
|
||||
props: {
|
||||
sessionId: commonProps.sessionId,
|
||||
},
|
||||
async run(context) {
|
||||
const sessionId = context.propsValue.sessionId as string;
|
||||
const client = new HedyApiClient(context.auth.secret_text);
|
||||
const response = await client.request<Session>({
|
||||
method: HttpMethod.GET,
|
||||
path: `/sessions/${sessionId}`,
|
||||
});
|
||||
|
||||
return unwrapResource(response);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './get-session';
|
||||
export * from './list-sessions';
|
||||
@@ -0,0 +1,42 @@
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { hedyAuth } from '../../auth';
|
||||
import { HedyApiClient } from '../../common/client';
|
||||
import { commonProps } from '../../common/props';
|
||||
import { topicDropdown } from '../../common/load-options';
|
||||
import { Session } from '../../common/types';
|
||||
import { assertLimit } from '../../common/validation';
|
||||
|
||||
export const listSessions = createAction({
|
||||
auth: hedyAuth,
|
||||
name: 'list-sessions',
|
||||
displayName: 'List Sessions',
|
||||
description: 'Retrieve multiple sessions with optional topic filtering and pagination.',
|
||||
props: {
|
||||
returnAll: commonProps.returnAll,
|
||||
limit: commonProps.limit,
|
||||
format: commonProps.format,
|
||||
topicId: topicDropdown,
|
||||
after: commonProps.afterCursor,
|
||||
before: commonProps.beforeCursor,
|
||||
},
|
||||
async run(context) {
|
||||
const client = new HedyApiClient(context.auth.secret_text);
|
||||
const { returnAll, limit, format, topicId, after, before } = context.propsValue as {
|
||||
returnAll?: boolean;
|
||||
limit?: number;
|
||||
format?: 'standard' | 'zapier';
|
||||
topicId?: string;
|
||||
after?: string;
|
||||
before?: string;
|
||||
};
|
||||
|
||||
return client.paginate<Session>('/sessions', {
|
||||
returnAll: Boolean(returnAll),
|
||||
limit: assertLimit(limit),
|
||||
format,
|
||||
topicId,
|
||||
after,
|
||||
before,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './list-todos';
|
||||
export * from './list-session-todos';
|
||||
@@ -0,0 +1,56 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { hedyAuth } from '../../auth';
|
||||
import { HedyApiClient } from '../../common/client';
|
||||
import { commonProps } from '../../common/props';
|
||||
import { PaginatedResponse, Todo } from '../../common/types';
|
||||
import { assertLimit } from '../../common/validation';
|
||||
|
||||
function toTodoArray(result: unknown): Todo[] {
|
||||
if (Array.isArray(result)) {
|
||||
return result as Todo[];
|
||||
}
|
||||
|
||||
if (result && typeof result === 'object' && 'data' in result) {
|
||||
const data = (result as PaginatedResponse<Todo>).data;
|
||||
if (Array.isArray(data)) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
export const listSessionTodos = createAction({
|
||||
auth: hedyAuth,
|
||||
name: 'list-session-todos',
|
||||
displayName: 'List Session Todos',
|
||||
description: 'Retrieve todos generated for a specific session.',
|
||||
props: {
|
||||
sessionId: commonProps.sessionId,
|
||||
returnAll: commonProps.returnAll,
|
||||
limit: commonProps.limit,
|
||||
},
|
||||
async run(context) {
|
||||
const sessionId = context.propsValue.sessionId as string;
|
||||
const client = new HedyApiClient(context.auth.secret_text);
|
||||
const { returnAll, limit } = context.propsValue as {
|
||||
returnAll?: boolean;
|
||||
limit?: number;
|
||||
};
|
||||
|
||||
const response = await client.request<Todo[]>({
|
||||
method: HttpMethod.GET,
|
||||
path: `/sessions/${sessionId}/todos`,
|
||||
});
|
||||
|
||||
const todos = toTodoArray(response);
|
||||
|
||||
if (!returnAll) {
|
||||
const limited = assertLimit(limit);
|
||||
return limited ? todos.slice(0, limited) : todos.slice(0, 50);
|
||||
}
|
||||
|
||||
return todos;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,54 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { hedyAuth } from '../../auth';
|
||||
import { HedyApiClient } from '../../common/client';
|
||||
import { commonProps } from '../../common/props';
|
||||
import { PaginatedResponse, Todo } from '../../common/types';
|
||||
import { assertLimit } from '../../common/validation';
|
||||
|
||||
function extractTodos(result: unknown): Todo[] {
|
||||
if (Array.isArray(result)) {
|
||||
return result as Todo[];
|
||||
}
|
||||
|
||||
if (result && typeof result === 'object' && 'data' in result) {
|
||||
const data = (result as PaginatedResponse<Todo>).data;
|
||||
if (Array.isArray(data)) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
export const listTodos = createAction({
|
||||
auth: hedyAuth,
|
||||
name: 'list-todos',
|
||||
displayName: 'List Todos',
|
||||
description: 'Retrieve todos assigned to you in Hedy.',
|
||||
props: {
|
||||
returnAll: commonProps.returnAll,
|
||||
limit: commonProps.limit,
|
||||
},
|
||||
async run(context) {
|
||||
const client = new HedyApiClient(context.auth.secret_text);
|
||||
const { returnAll, limit } = context.propsValue as {
|
||||
returnAll?: boolean;
|
||||
limit?: number;
|
||||
};
|
||||
|
||||
const response = await client.request<Todo[]>({
|
||||
method: HttpMethod.GET,
|
||||
path: '/todos',
|
||||
});
|
||||
|
||||
const todos = extractTodos(response);
|
||||
|
||||
if (!returnAll) {
|
||||
const limited = assertLimit(limit);
|
||||
return limited ? todos.slice(0, limited) : todos.slice(0, 50);
|
||||
}
|
||||
|
||||
return todos;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { hedyAuth } from '../../auth';
|
||||
import { HedyApiClient, unwrapResource } from '../../common/client';
|
||||
import { commonProps } from '../../common/props';
|
||||
import { Topic } from '../../common/types';
|
||||
|
||||
export const getTopic = createAction({
|
||||
auth: hedyAuth,
|
||||
name: 'get-topic',
|
||||
displayName: 'Get Topic',
|
||||
description: 'Retrieve details for a specific topic.',
|
||||
props: {
|
||||
topicId: commonProps.topicId,
|
||||
},
|
||||
async run(context) {
|
||||
const topicId = context.propsValue.topicId as string;
|
||||
const client = new HedyApiClient(context.auth.secret_text);
|
||||
const response = await client.request<Topic>({
|
||||
method: HttpMethod.GET,
|
||||
path: `/topics/${topicId}`,
|
||||
});
|
||||
|
||||
return unwrapResource(response);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './get-topic';
|
||||
export * from './list-topics';
|
||||
export * from './list-topic-sessions';
|
||||
@@ -0,0 +1,56 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { hedyAuth } from '../../auth';
|
||||
import { HedyApiClient } from '../../common/client';
|
||||
import { commonProps } from '../../common/props';
|
||||
import { PaginatedResponse, Session } from '../../common/types';
|
||||
import { assertLimit } from '../../common/validation';
|
||||
|
||||
function toSessionArray(result: unknown): Session[] {
|
||||
if (Array.isArray(result)) {
|
||||
return result as Session[];
|
||||
}
|
||||
|
||||
if (result && typeof result === 'object' && 'data' in result) {
|
||||
const data = (result as PaginatedResponse<Session>).data;
|
||||
if (Array.isArray(data)) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
export const listTopicSessions = createAction({
|
||||
auth: hedyAuth,
|
||||
name: 'list-topic-sessions',
|
||||
displayName: 'List Topic Sessions',
|
||||
description: 'Retrieve sessions associated with a specific topic.',
|
||||
props: {
|
||||
topicId: commonProps.topicId,
|
||||
returnAll: commonProps.returnAll,
|
||||
limit: commonProps.limit,
|
||||
},
|
||||
async run(context) {
|
||||
const topicId = context.propsValue.topicId as string;
|
||||
const client = new HedyApiClient(context.auth.secret_text);
|
||||
const { returnAll, limit } = context.propsValue as {
|
||||
returnAll?: boolean;
|
||||
limit?: number;
|
||||
};
|
||||
|
||||
const response = await client.request<Session[]>({
|
||||
method: HttpMethod.GET,
|
||||
path: `/topics/${topicId}/sessions`,
|
||||
});
|
||||
|
||||
const sessions = toSessionArray(response);
|
||||
|
||||
if (!returnAll) {
|
||||
const limited = assertLimit(limit);
|
||||
return limited ? sessions.slice(0, limited) : sessions.slice(0, 50);
|
||||
}
|
||||
|
||||
return sessions;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,54 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { hedyAuth } from '../../auth';
|
||||
import { HedyApiClient } from '../../common/client';
|
||||
import { commonProps } from '../../common/props';
|
||||
import { PaginatedResponse, Topic } from '../../common/types';
|
||||
import { assertLimit } from '../../common/validation';
|
||||
|
||||
function toTopicArray(result: unknown): Topic[] {
|
||||
if (Array.isArray(result)) {
|
||||
return result as Topic[];
|
||||
}
|
||||
|
||||
if (result && typeof result === 'object' && 'data' in result) {
|
||||
const data = (result as PaginatedResponse<Topic>).data;
|
||||
if (Array.isArray(data)) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
export const listTopics = createAction({
|
||||
auth: hedyAuth,
|
||||
name: 'list-topics',
|
||||
displayName: 'List Topics',
|
||||
description: 'Retrieve all topics from your Hedy workspace.',
|
||||
props: {
|
||||
returnAll: commonProps.returnAll,
|
||||
limit: commonProps.limit,
|
||||
},
|
||||
async run(context) {
|
||||
const client = new HedyApiClient(context.auth.secret_text);
|
||||
const { returnAll, limit } = context.propsValue as {
|
||||
returnAll?: boolean;
|
||||
limit?: number;
|
||||
};
|
||||
|
||||
const response = await client.request<Topic[]>({
|
||||
method: HttpMethod.GET,
|
||||
path: '/topics',
|
||||
});
|
||||
|
||||
const topics = toTopicArray(response);
|
||||
|
||||
if (!returnAll) {
|
||||
const limited = assertLimit(limit);
|
||||
return limited ? topics.slice(0, limited) : topics.slice(0, 50);
|
||||
}
|
||||
|
||||
return topics;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { PieceAuth } from '@activepieces/pieces-framework';
|
||||
import { HedyApiClient } from '../common/client';
|
||||
|
||||
export const hedyAuth = PieceAuth.SecretText({
|
||||
displayName: 'API Key',
|
||||
description:
|
||||
'Generate an API key from your Hedy dashboard under Settings → API, then paste the key here (it begins with `hedy_live_`).',
|
||||
required: true,
|
||||
validate: async ({ auth }) => {
|
||||
if (!auth || typeof auth !== 'string') {
|
||||
return {
|
||||
valid: false,
|
||||
error: 'Please provide a valid API key.',
|
||||
};
|
||||
}
|
||||
|
||||
const client = new HedyApiClient(auth);
|
||||
try {
|
||||
await client.request({
|
||||
method: HttpMethod.GET,
|
||||
path: '/sessions',
|
||||
queryParams: {
|
||||
limit: 1,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
valid: true,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
valid: false,
|
||||
error:
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: 'Invalid API key. Please verify the key in your Hedy dashboard and try again.',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,203 @@
|
||||
import {
|
||||
AuthenticationType,
|
||||
httpClient,
|
||||
HttpMethod,
|
||||
HttpRequest,
|
||||
QueryParams,
|
||||
} from '@activepieces/pieces-common';
|
||||
import { HedyApiError } from './errors';
|
||||
import {
|
||||
ApiErrorPayload,
|
||||
HedyResponse,
|
||||
PaginatedResponse,
|
||||
PaginationInfo,
|
||||
} from './types';
|
||||
|
||||
const BASE_URL = 'https://api.hedy.bot';
|
||||
const DEFAULT_LIMIT = 50;
|
||||
const MAX_RESULTS = 1000;
|
||||
const MAX_RETRIES = 3;
|
||||
const INITIAL_BACKOFF_MS = 500;
|
||||
|
||||
export interface PaginationOptions {
|
||||
returnAll?: boolean;
|
||||
limit?: number;
|
||||
after?: string;
|
||||
before?: string;
|
||||
topicId?: string;
|
||||
format?: 'standard' | 'zapier';
|
||||
}
|
||||
|
||||
interface RequestOptions {
|
||||
method: HttpMethod;
|
||||
path: string;
|
||||
body?: unknown;
|
||||
queryParams?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export class HedyApiClient {
|
||||
constructor(private readonly apiKey: string) {}
|
||||
|
||||
async request<T>(options: RequestOptions): Promise<HedyResponse<T>> {
|
||||
return this.withRetry(() => this.performRequest<T>(options));
|
||||
}
|
||||
|
||||
async paginate<T>(path: string, options: PaginationOptions = {}): Promise<T[]> {
|
||||
const { returnAll = false, limit = DEFAULT_LIMIT, ...rest } = options;
|
||||
const collected: T[] = [];
|
||||
let cursor = rest.after;
|
||||
let hasMore = true;
|
||||
|
||||
while (hasMore) {
|
||||
const query = {
|
||||
...rest,
|
||||
limit: returnAll ? Math.min(limit, 100) : limit,
|
||||
after: cursor,
|
||||
};
|
||||
|
||||
const response = await this.request<T>({
|
||||
method: HttpMethod.GET,
|
||||
path,
|
||||
queryParams: query,
|
||||
});
|
||||
|
||||
const { data, pagination } = normalizeListResult(response);
|
||||
collected.push(...data);
|
||||
|
||||
if (!returnAll && collected.length >= limit) {
|
||||
// When NOT returning all, stop when we hit the limit
|
||||
hasMore = false;
|
||||
} else if (pagination?.hasMore && pagination.next) {
|
||||
// Continue if there's more data available
|
||||
cursor = pagination.next;
|
||||
hasMore = true;
|
||||
} else {
|
||||
// No more data available
|
||||
hasMore = false;
|
||||
}
|
||||
|
||||
if (collected.length >= MAX_RESULTS) {
|
||||
hasMore = false;
|
||||
}
|
||||
}
|
||||
|
||||
return returnAll ? collected : collected.slice(0, limit);
|
||||
}
|
||||
|
||||
private async performRequest<T>({ method, path, body, queryParams }: RequestOptions): Promise<HedyResponse<T>> {
|
||||
const qs: QueryParams = {};
|
||||
|
||||
if (queryParams) {
|
||||
for (const [key, value] of Object.entries(queryParams)) {
|
||||
if (value === undefined || value === null || value === '') {
|
||||
continue;
|
||||
}
|
||||
qs[key] = String(value);
|
||||
}
|
||||
}
|
||||
|
||||
const request: HttpRequest = {
|
||||
method,
|
||||
url: `${BASE_URL}${path}`,
|
||||
authentication: {
|
||||
type: AuthenticationType.BEARER_TOKEN,
|
||||
token: this.apiKey,
|
||||
},
|
||||
headers: {
|
||||
'User-Agent': 'activepieces-hedy/1.0.0',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body,
|
||||
queryParams: qs,
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await httpClient.sendRequest<HedyResponse<T>>(request);
|
||||
const { body: responseBody } = response;
|
||||
|
||||
if (isErrorPayload(responseBody)) {
|
||||
throw HedyApiError.fromPayload(responseBody, undefined, response.status);
|
||||
}
|
||||
|
||||
return responseBody;
|
||||
} catch (error: any) {
|
||||
const apiErrorPayload: ApiErrorPayload | undefined = error?.response?.body;
|
||||
const statusCode: number | undefined = error?.response?.status;
|
||||
throw HedyApiError.fromPayload(apiErrorPayload, error, statusCode);
|
||||
}
|
||||
}
|
||||
|
||||
private async withRetry<T>(operation: () => Promise<T>): Promise<T> {
|
||||
let attempt = 0;
|
||||
let backoff = INITIAL_BACKOFF_MS;
|
||||
|
||||
while (attempt < MAX_RETRIES) {
|
||||
try {
|
||||
return await operation();
|
||||
} catch (error) {
|
||||
const isLastAttempt = attempt === MAX_RETRIES - 1;
|
||||
if (!(error instanceof HedyApiError) || !this.shouldRetry(error) || isLastAttempt) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
await this.delay(backoff);
|
||||
backoff *= 2;
|
||||
attempt += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// The loop above either returns or throws, but TypeScript expects a return.
|
||||
throw new HedyApiError('unknown_error', 'Request failed after multiple retries.');
|
||||
}
|
||||
|
||||
private shouldRetry(error: HedyApiError): boolean {
|
||||
return error.code === 'rate_limit_exceeded';
|
||||
}
|
||||
|
||||
private async delay(duration: number): Promise<void> {
|
||||
await new Promise((resolve) => setTimeout(resolve, duration));
|
||||
}
|
||||
}
|
||||
|
||||
function isErrorPayload<T>(body: HedyResponse<T>): body is ApiErrorPayload {
|
||||
return Boolean(body && typeof body === 'object' && 'error' in body);
|
||||
}
|
||||
|
||||
function normalizeListResult<T>(result: HedyResponse<T>): {
|
||||
data: T[];
|
||||
pagination?: PaginationInfo;
|
||||
} {
|
||||
if (Array.isArray(result)) {
|
||||
return { data: result };
|
||||
}
|
||||
|
||||
if (result && typeof result === 'object') {
|
||||
const maybePaginated = result as PaginatedResponse<T>;
|
||||
if (Array.isArray(maybePaginated.data)) {
|
||||
return {
|
||||
data: maybePaginated.data,
|
||||
pagination: maybePaginated.pagination,
|
||||
};
|
||||
}
|
||||
|
||||
const maybeData = (result as { data?: unknown }).data;
|
||||
if (Array.isArray(maybeData)) {
|
||||
return { data: maybeData as T[] };
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
data: result ? [result as T] : [],
|
||||
};
|
||||
}
|
||||
|
||||
export function unwrapResource<T>(result: HedyResponse<T>): T {
|
||||
if (result && typeof result === 'object') {
|
||||
const data = (result as { data?: unknown }).data;
|
||||
if (data && !Array.isArray(data)) {
|
||||
return data as T;
|
||||
}
|
||||
}
|
||||
|
||||
return result as T;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import { ApiErrorPayload } from './types';
|
||||
|
||||
const DEFAULT_ERROR_MESSAGE = 'An unknown error occurred while communicating with Hedy.';
|
||||
|
||||
function deriveCode(initialCode: string | undefined, statusCode?: number): string {
|
||||
if (initialCode) {
|
||||
return initialCode;
|
||||
}
|
||||
|
||||
if (statusCode === 429) {
|
||||
return 'rate_limit_exceeded';
|
||||
}
|
||||
|
||||
return 'unknown_error';
|
||||
}
|
||||
|
||||
const FRIENDLY_MESSAGES: Record<string, string> = {
|
||||
webhook_limit_exceeded:
|
||||
'Maximum webhook limit (10) reached. Please delete unused webhooks in your Hedy dashboard.',
|
||||
authentication_failed:
|
||||
'Invalid API key. Please check your Hedy dashboard for the correct API key.',
|
||||
invalid_event:
|
||||
'Invalid event type. Valid events: session.created, session.ended, highlight.created, todo.exported.',
|
||||
invalid_webhook_url:
|
||||
'Webhook URL must be publicly accessible. For local testing, use a tunneling service like ngrok.',
|
||||
invalid_parameter:
|
||||
'Invalid request parameter. Please review your configuration and try again.',
|
||||
rate_limit_exceeded:
|
||||
'Rate limit reached. Please wait a moment before trying again.',
|
||||
unknown_error: DEFAULT_ERROR_MESSAGE,
|
||||
};
|
||||
|
||||
export class HedyApiError extends Error {
|
||||
constructor(
|
||||
public readonly code: string,
|
||||
message: string,
|
||||
public readonly details?: unknown,
|
||||
) {
|
||||
super(message || DEFAULT_ERROR_MESSAGE);
|
||||
this.name = 'HedyApiError';
|
||||
}
|
||||
|
||||
static fromPayload(
|
||||
payload: ApiErrorPayload | undefined,
|
||||
fallback?: unknown,
|
||||
statusCode?: number,
|
||||
): HedyApiError {
|
||||
if (payload && payload.error) {
|
||||
const { code, message } = payload.error;
|
||||
const resolvedCode = deriveCode(code, statusCode);
|
||||
return new HedyApiError(
|
||||
resolvedCode,
|
||||
FRIENDLY_MESSAGES[resolvedCode] ?? message ?? DEFAULT_ERROR_MESSAGE,
|
||||
payload,
|
||||
);
|
||||
}
|
||||
|
||||
if (fallback instanceof HedyApiError) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
if (fallback instanceof Error) {
|
||||
const derivedCode = deriveCode(undefined, statusCode);
|
||||
return new HedyApiError(
|
||||
derivedCode,
|
||||
FRIENDLY_MESSAGES[derivedCode] ?? fallback.message ?? DEFAULT_ERROR_MESSAGE,
|
||||
fallback,
|
||||
);
|
||||
}
|
||||
|
||||
const finalCode = deriveCode(undefined, statusCode);
|
||||
return new HedyApiError(
|
||||
finalCode,
|
||||
FRIENDLY_MESSAGES[finalCode] ?? DEFAULT_ERROR_MESSAGE,
|
||||
fallback,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { Property } from '@activepieces/pieces-framework';
|
||||
import { HedyApiClient } from './client';
|
||||
import { PaginatedResponse, Topic } from './types';
|
||||
import { hedyAuth } from '../auth';
|
||||
|
||||
function toTopicArray(result: unknown): Topic[] {
|
||||
if (Array.isArray(result)) {
|
||||
return result as Topic[];
|
||||
}
|
||||
|
||||
if (result && typeof result === 'object' && 'data' in result) {
|
||||
const data = (result as PaginatedResponse<Topic>).data;
|
||||
if (Array.isArray(data)) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
export const topicDropdown = Property.Dropdown({
|
||||
auth: hedyAuth,
|
||||
displayName: 'Topic',
|
||||
description: 'Optionally filter results by a specific topic.',
|
||||
required: false,
|
||||
refreshers: [],
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Connect your Hedy account first.',
|
||||
};
|
||||
}
|
||||
|
||||
const client = new HedyApiClient(auth.secret_text);
|
||||
try {
|
||||
const response = await client.request<Topic[]>({
|
||||
method: HttpMethod.GET,
|
||||
path: '/topics',
|
||||
});
|
||||
|
||||
const topics = toTopicArray(response);
|
||||
|
||||
if (topics.length === 0) {
|
||||
return {
|
||||
disabled: false,
|
||||
options: [],
|
||||
placeholder: 'No topics found in your Hedy workspace.',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options: topics.map((topic) => ({
|
||||
label: topic.name,
|
||||
value: topic.id,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder:
|
||||
error instanceof Error ? error.message : 'Failed to load topics. Check your connection.',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
import { Property } from '@activepieces/pieces-framework';
|
||||
|
||||
export const commonProps = {
|
||||
sessionId: Property.ShortText({
|
||||
displayName: 'Session ID',
|
||||
description: 'The session ID as shown in the Hedy dashboard.',
|
||||
required: true,
|
||||
}),
|
||||
|
||||
highlightId: Property.ShortText({
|
||||
displayName: 'Highlight ID',
|
||||
description: 'The highlight ID as shown in the Hedy dashboard.',
|
||||
required: true,
|
||||
}),
|
||||
|
||||
topicId: Property.ShortText({
|
||||
displayName: 'Topic ID',
|
||||
description: 'The topic ID as shown in the Hedy dashboard.',
|
||||
required: true,
|
||||
}),
|
||||
|
||||
returnAll: Property.Checkbox({
|
||||
displayName: 'Return All',
|
||||
description: 'Return all results instead of using the limit.',
|
||||
required: false,
|
||||
defaultValue: false,
|
||||
}),
|
||||
|
||||
limit: Property.Number({
|
||||
displayName: 'Limit',
|
||||
description: 'Maximum number of results to return (default 50).',
|
||||
required: false,
|
||||
defaultValue: 50,
|
||||
}),
|
||||
|
||||
format: Property.StaticDropdown({
|
||||
displayName: 'Response Format',
|
||||
description: 'Select the response format to use.',
|
||||
required: false,
|
||||
defaultValue: 'standard',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Standard', value: 'standard' },
|
||||
{ label: 'Zapier Compatible', value: 'zapier' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
|
||||
afterCursor: Property.ShortText({
|
||||
displayName: 'After Cursor',
|
||||
description: 'Pagination cursor used to fetch results after a specific item.',
|
||||
required: false,
|
||||
}),
|
||||
|
||||
beforeCursor: Property.ShortText({
|
||||
displayName: 'Before Cursor',
|
||||
description: 'Pagination cursor used to fetch results before a specific item.',
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
@@ -0,0 +1,103 @@
|
||||
export interface Topic {
|
||||
id: string;
|
||||
name: string;
|
||||
color?: string;
|
||||
iconName?: string;
|
||||
}
|
||||
|
||||
export interface Todo {
|
||||
id: string;
|
||||
text: string;
|
||||
dueDate?: string;
|
||||
completed: boolean;
|
||||
topic?: Topic;
|
||||
}
|
||||
|
||||
export interface Conversation {
|
||||
question: string;
|
||||
answer: string;
|
||||
timestamp?: string;
|
||||
}
|
||||
|
||||
export interface Session {
|
||||
id: string;
|
||||
title: string;
|
||||
startTime: string;
|
||||
endTime?: string;
|
||||
duration?: number;
|
||||
transcript?: string;
|
||||
conversations?: Conversation[] | string;
|
||||
meeting_minutes?: string;
|
||||
meetingMinutes?: string;
|
||||
recap?: string;
|
||||
user_todos?: Todo[];
|
||||
userTodos?: Todo[];
|
||||
topic?: Topic;
|
||||
}
|
||||
|
||||
export interface Highlight {
|
||||
id: string;
|
||||
sessionId: string;
|
||||
timestamp?: string;
|
||||
title?: string;
|
||||
rawQuote?: string;
|
||||
cleanedQuote?: string;
|
||||
mainIdea?: string;
|
||||
aiInsights?: string;
|
||||
}
|
||||
|
||||
export interface TodoExportedPayload {
|
||||
id: string;
|
||||
sessionId: string;
|
||||
text: string;
|
||||
dueDate?: string;
|
||||
}
|
||||
|
||||
export interface PaginationInfo {
|
||||
hasMore: boolean;
|
||||
next?: string;
|
||||
previous?: string;
|
||||
}
|
||||
|
||||
export interface PaginatedResponse<T> {
|
||||
success?: boolean;
|
||||
data: T[];
|
||||
pagination?: PaginationInfo;
|
||||
}
|
||||
|
||||
export interface ApiSuccessResponse<T> {
|
||||
success: true;
|
||||
data: T;
|
||||
}
|
||||
|
||||
export interface ApiErrorPayload {
|
||||
success?: false;
|
||||
error: {
|
||||
code: string;
|
||||
message: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type HedyResponse<T> =
|
||||
| T
|
||||
| T[]
|
||||
| PaginatedResponse<T>
|
||||
| ApiSuccessResponse<T>
|
||||
| ApiErrorPayload;
|
||||
|
||||
export interface WebhookRegistration {
|
||||
id?: string;
|
||||
url: string;
|
||||
events: string[];
|
||||
signingSecret?: string;
|
||||
createdAt?: string;
|
||||
updatedAt?: string;
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export enum HedyWebhookEvent {
|
||||
SessionCreated = 'session.created',
|
||||
SessionEnded = 'session.ended',
|
||||
HighlightCreated = 'highlight.created',
|
||||
TodoExported = 'todo.exported',
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
export function assertLimit(limit?: number): number | undefined {
|
||||
if (limit === undefined || limit === null) {
|
||||
return limit ?? undefined;
|
||||
}
|
||||
|
||||
if (Number.isNaN(limit)) {
|
||||
throw new Error('Limit must be a number between 1 and 100.');
|
||||
}
|
||||
|
||||
if (limit < 1 || limit > 100) {
|
||||
throw new Error('Limit must be between 1 and 100.');
|
||||
}
|
||||
|
||||
return limit;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './webhook';
|
||||
@@ -0,0 +1,157 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { Property, TriggerStrategy, createTrigger } from '@activepieces/pieces-framework';
|
||||
import { createHmac, timingSafeEqual } from 'crypto';
|
||||
import { hedyAuth } from '../../auth';
|
||||
import { HedyApiClient, unwrapResource } from '../../common/client';
|
||||
import { HedyWebhookEvent, WebhookRegistration } from '../../common/types';
|
||||
|
||||
interface TriggerConfig {
|
||||
event: HedyWebhookEvent;
|
||||
name: string;
|
||||
displayName: string;
|
||||
description: string;
|
||||
sampleData?: unknown;
|
||||
}
|
||||
|
||||
export function createHedyWebhookTrigger(config: TriggerConfig) {
|
||||
return createTrigger({
|
||||
auth: hedyAuth,
|
||||
name: config.name,
|
||||
displayName: config.displayName,
|
||||
description: config.description,
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
props: {
|
||||
verifySignature: Property.Checkbox({
|
||||
displayName: 'Verify Signature',
|
||||
description:
|
||||
'Verify the webhook signature using the secret returned by Hedy. Disable this option if Hedy does not provide a signing secret for your account.',
|
||||
required: false,
|
||||
defaultValue: false,
|
||||
}),
|
||||
},
|
||||
sampleData: config.sampleData,
|
||||
async onEnable(context) {
|
||||
const client = new HedyApiClient(context.auth.secret_text);
|
||||
const webhookUrl = context.webhookUrl;
|
||||
|
||||
if (!webhookUrl) {
|
||||
throw new Error('Webhook URL is unavailable. Please try again.');
|
||||
}
|
||||
|
||||
const response = await client.request<WebhookRegistration>({
|
||||
method: HttpMethod.POST,
|
||||
path: '/webhooks',
|
||||
body: {
|
||||
url: webhookUrl,
|
||||
events: [config.event],
|
||||
},
|
||||
});
|
||||
|
||||
const webhook = unwrapResource<WebhookRegistration>(response);
|
||||
|
||||
if (!webhook?.id) {
|
||||
throw new Error('Failed to register webhook with Hedy. No webhook ID was returned.');
|
||||
}
|
||||
|
||||
await context.store.put('webhookId', webhook.id);
|
||||
|
||||
if (webhook.signingSecret) {
|
||||
await context.store.put('signingSecret', webhook.signingSecret);
|
||||
} else {
|
||||
await context.store.delete('signingSecret');
|
||||
}
|
||||
},
|
||||
async onDisable(context) {
|
||||
const webhookId = (await context.store.get<string>('webhookId')) ?? undefined;
|
||||
if (!webhookId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const client = new HedyApiClient(context.auth.secret_text);
|
||||
try {
|
||||
await client.request({
|
||||
method: HttpMethod.DELETE,
|
||||
path: `/webhooks/${webhookId}`,
|
||||
});
|
||||
} catch (error) {
|
||||
// Ignore deletion errors – webhook may already be removed.
|
||||
} finally {
|
||||
await context.store.delete('webhookId');
|
||||
await context.store.delete('signingSecret');
|
||||
}
|
||||
},
|
||||
async run(context) {
|
||||
const props = context.propsValue as Record<string, unknown>;
|
||||
const verifySignatureEnabled = Boolean(props['verifySignature']);
|
||||
const payload = (context.payload.body ?? {}) as Record<string, unknown>;
|
||||
|
||||
if (verifySignatureEnabled) {
|
||||
const signatureHeader = getSignatureHeader(context.payload.headers ?? {});
|
||||
if (!signatureHeader) {
|
||||
throw new Error('Hedy signature header is missing from the webhook request.');
|
||||
}
|
||||
|
||||
const signingSecret = await context.store.get<string>('signingSecret');
|
||||
if (!signingSecret) {
|
||||
throw new Error(
|
||||
'Hedy did not return a signing secret during webhook registration. Disable signature verification or re-register your webhook.',
|
||||
);
|
||||
}
|
||||
|
||||
const rawBody = extractRawBody(context.payload.rawBody as RawBody, payload);
|
||||
const expectedSignature = createHmac('sha256', signingSecret).update(rawBody).digest('hex');
|
||||
|
||||
if (!secureCompare(expectedSignature, signatureHeader)) {
|
||||
throw new Error('Webhook signature verification failed. This request may not be from Hedy.');
|
||||
}
|
||||
}
|
||||
|
||||
const eventType = payload['event'] as string | undefined;
|
||||
if (eventType && eventType !== config.event) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [payload];
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
type HeadersMap = Record<string, string | string[] | undefined>;
|
||||
|
||||
type RawBody = string | Buffer | undefined;
|
||||
|
||||
function getSignatureHeader(headers: HeadersMap): string | undefined {
|
||||
const normalized: Record<string, string> = {};
|
||||
for (const [key, value] of Object.entries(headers)) {
|
||||
if (typeof value === 'string') {
|
||||
normalized[key.toLowerCase()] = value;
|
||||
} else if (Array.isArray(value) && value.length > 0) {
|
||||
normalized[key.toLowerCase()] = value[0];
|
||||
}
|
||||
}
|
||||
|
||||
return normalized['x-hedy-signature'];
|
||||
}
|
||||
|
||||
function extractRawBody(rawBody: RawBody, payload: Record<string, unknown>): Buffer {
|
||||
if (typeof rawBody === 'string') {
|
||||
return Buffer.from(rawBody, 'utf8');
|
||||
}
|
||||
|
||||
if (rawBody instanceof Buffer) {
|
||||
return rawBody;
|
||||
}
|
||||
|
||||
return Buffer.from(JSON.stringify(payload ?? {}), 'utf8');
|
||||
}
|
||||
|
||||
function secureCompare(expected: string, candidate: string): boolean {
|
||||
const expectedBuffer = Buffer.from(expected, 'hex');
|
||||
const candidateBuffer = Buffer.from(candidate, 'hex');
|
||||
|
||||
if (expectedBuffer.length !== candidateBuffer.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return timingSafeEqual(expectedBuffer, candidateBuffer);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { HedyWebhookEvent } from '../../common/types';
|
||||
import { createHedyWebhookTrigger } from './factory';
|
||||
|
||||
export const highlightCreated = createHedyWebhookTrigger({
|
||||
event: HedyWebhookEvent.HighlightCreated,
|
||||
name: 'highlight-created',
|
||||
displayName: 'Highlight Created',
|
||||
description: 'Triggers when a highlight is created during a session.',
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from './session-created';
|
||||
export * from './session-ended';
|
||||
export * from './highlight-created';
|
||||
export * from './todo-exported';
|
||||
@@ -0,0 +1,9 @@
|
||||
import { HedyWebhookEvent } from '../../common/types';
|
||||
import { createHedyWebhookTrigger } from './factory';
|
||||
|
||||
export const sessionCreated = createHedyWebhookTrigger({
|
||||
event: HedyWebhookEvent.SessionCreated,
|
||||
name: 'session-created',
|
||||
displayName: 'Session Created',
|
||||
description: 'Triggers when a new session is created in Hedy.',
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
import { HedyWebhookEvent } from '../../common/types';
|
||||
import { createHedyWebhookTrigger } from './factory';
|
||||
|
||||
export const sessionEnded = createHedyWebhookTrigger({
|
||||
event: HedyWebhookEvent.SessionEnded,
|
||||
name: 'session-ended',
|
||||
displayName: 'Session Ended',
|
||||
description: 'Triggers when a session is completed in Hedy.',
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
import { HedyWebhookEvent } from '../../common/types';
|
||||
import { createHedyWebhookTrigger } from './factory';
|
||||
|
||||
export const todoExported = createHedyWebhookTrigger({
|
||||
event: HedyWebhookEvent.TodoExported,
|
||||
name: 'todo-exported',
|
||||
displayName: 'Todo Exported',
|
||||
description: 'Triggers when a todo item is exported from Hedy.',
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"extends": "../../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"importHelpers": true,
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noPropertyAccessFromIndexSignature": true
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../../dist/out-tsc",
|
||||
"declaration": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user