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:
poduck
2025-12-18 22:59:37 -05:00
parent 9848268d34
commit 3aa7199503
16292 changed files with 1284892 additions and 4708 deletions

View File

@@ -0,0 +1,33 @@
{
"extends": [
"../../../../.eslintrc.base.json"
],
"ignorePatterns": [
"!**/*"
],
"overrides": [
{
"files": [
"*.ts",
"*.tsx",
"*.js",
"*.jsx"
],
"rules": {}
},
{
"files": [
"*.ts",
"*.tsx"
],
"rules": {}
},
{
"files": [
"*.js",
"*.jsx"
],
"rules": {}
}
]
}

View File

@@ -0,0 +1,7 @@
# pieces-greip
This library was generated with [Nx](https://nx.dev).
## Building
Run `nx build pieces-greip` to build the library.

View File

@@ -0,0 +1,10 @@
{
"name": "@activepieces/piece-greip",
"version": "0.0.2",
"type": "commonjs",
"main": "./src/index.js",
"types": "./src/index.d.ts",
"dependencies": {
"tslib": "^2.3.0"
}
}

View File

@@ -0,0 +1,65 @@
{
"name": "pieces-greip",
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/pieces/community/greip/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/greip",
"tsConfig": "packages/pieces/community/greip/tsconfig.lib.json",
"packageJson": "packages/pieces/community/greip/package.json",
"main": "packages/pieces/community/greip/src/index.ts",
"assets": [
"packages/pieces/community/greip/*.md",
{
"input": "packages/pieces/community/greip/src/i18n",
"output": "./src/i18n",
"glob": "**/!(i18n.json)"
}
],
"buildableProjectDepsInPackageJsonType": "dependencies",
"updateBuildableProjectDepsInPackageJson": true
},
"dependsOn": [
"prebuild",
"^build"
]
},
"nx-release-publish": {
"options": {
"packageRoot": "dist/{projectRoot}"
}
},
"prebuild": {
"dependsOn": [
"^build"
],
"executor": "nx:run-commands",
"options": {
"cwd": "packages/pieces/community/greip",
"command": "bun install --no-save --silent"
}
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": [
"{options.outputFile}"
]
}
}
}

View File

@@ -0,0 +1,78 @@
{
"Detect and prevent fraud in your website or app with Greip's Fraud Prevention API. Protect your business from financial losses and gain better insights into your users.": "Detect and prevent fraud in your website or app with Greip's Fraud Prevention API. Protect your business from financial losses and gain better insights into your users.",
"\nTo get your API Key:\n\n1. Go to your Greip account dashboard\n2. Navigate to API settings\n3. Copy your API key\n4. Paste it here\n": "\nTo get your API Key:\n\n1. Go to your Greip account dashboard\n2. Navigate to API settings\n3. Copy your API key\n4. Paste it here\n",
"ASN Lookup": "ASN Lookup",
"BIN Lookup": "BIN Lookup",
"IP Lookup": "IP Lookup",
"Email Validation": "Email Validation",
"Detect Profanity": "Detect Profanity",
"Phone Validation": "Phone Validation",
"Look up details of an Autonomous System Number (ASN)": "Look up details of an Autonomous System Number (ASN)",
"Look up details of a Bank Identification Number (BIN) or Issuer Identification Number (IIN)": "Look up details of a Bank Identification Number (BIN) or Issuer Identification Number (IIN)",
"Look up comprehensive information about an IP address including location, ISP, security, and risk factors": "Look up comprehensive information about an IP address including location, ISP, security, and risk factors",
"Validate email addresses by checking domain validity, detecting disposable emails, and assessing risk factors": "Validate email addresses by checking domain validity, detecting disposable emails, and assessing risk factors",
"Detect offensive or inappropriate language in text using machine learning": "Detect offensive or inappropriate language in text using machine learning",
"Validate phone numbers by checking syntax and assessing validity and operational status": "Validate phone numbers by checking syntax and assessing validity and operational status",
"AS Number": "AS Number",
"Response Format": "Response Format",
"Environment": "Environment",
"JSONP Callback": "JSONP Callback",
"BIN/IIN": "BIN/IIN",
"User Identifier": "User Identifier",
"IP Address": "IP Address",
"Modules": "Modules",
"Response Language": "Response Language",
"Email Address": "Email Address",
"Text": "Text",
"Score Only": "Score Only",
"List Bad Words": "List Bad Words",
"Phone Number": "Phone Number",
"Country Code": "Country Code",
"The AS Number to lookup (e.g., AS6167 or 6167)": "The AS Number to lookup (e.g., AS6167 or 6167)",
"Format of the response": "Format of the response",
"Environment mode for testing or production": "Environment mode for testing or production",
"Function name for JSONP response format": "Function name for JSONP response format",
"The BIN/IIN of the card (minimum 6 digits). Can be partial like \"456789\" or full card number": "The BIN/IIN of the card (minimum 6 digits). Can be partial like \"456789\" or full card number",
"Identify requests from specific users for monitoring (e.g., email, phone, user ID)": "Identify requests from specific users for monitoring (e.g., email, phone, user ID)",
"The IP address to lookup (IPv4 or IPv6)": "The IP address to lookup (IPv4 or IPv6)",
"Comma-separated list of modules to include: security, currency, timezone, location (e.g., \"security,timezone,currency\")": "Comma-separated list of modules to include: security, currency, timezone, location (e.g., \"security,timezone,currency\")",
"Language for the response": "Language for the response",
"The email address to validate": "The email address to validate",
"The text to check for profanity": "The text to check for profanity",
"Return only the score and safety status": "Return only the score and safety status",
"Include a list of bad words found in the text": "Include a list of bad words found in the text",
"The phone number to validate (e.g., +12121234567, 0012121234567, 12121234567, or 2121234567)": "The phone number to validate (e.g., +12121234567, 0012121234567, 12121234567, or 2121234567)",
"ISO 3166-1 alpha-2 country code (e.g., US, GB, FR)": "ISO 3166-1 alpha-2 country code (e.g., US, GB, FR)",
"JSON": "JSON",
"XML": "XML",
"CSV": "CSV",
"Newline": "Newline",
"Live": "Live",
"Test": "Test",
"English": "English",
"Arabic": "Arabic",
"German": "German",
"French": "French",
"Spanish": "Spanish",
"Japanese": "Japanese",
"Chinese": "Chinese",
"Russian": "Russian",
"No": "No",
"Yes": "Yes",
"Proxy Connection Detected": "Proxy Connection Detected",
"Fraudulent Payment Detected": "Fraudulent Payment Detected",
"Profanity Text Detected": "Profanity Text Detected",
"Spam Email Detected": "Spam Email Detected",
"Spam Phone Number Detected": "Spam Phone Number Detected",
"Triggers when a new proxy connection is detected": "Triggers when a new proxy connection is detected",
"Triggers when a new fraudulent payment is detected by Greip": "Triggers when a new fraudulent payment is detected by Greip",
"Triggers when Greip detects profanity in a specific text": "Triggers when Greip detects profanity in a specific text",
"Triggers when a new email is marked as SPAM by Greip": "Triggers when a new email is marked as SPAM by Greip",
"Triggers when a new phone number is marked as SPAM by Greip": "Triggers when a new phone number is marked as SPAM by Greip",
"Markdown": "Markdown",
"\nTo use this trigger, you need to manually set up a webhook in your Greip account:\n\n1. Login to your Greip dashboard.\n2. Go to Settings > Integrations > Webhooks.\n3. Click on \"Add Webhook\" or \"Create New Webhook\".\n4. Add the following URL in the **Webhook URL** field:\n```text\n{{webhookUrl}}\n```\n5. Select **proxy_detected** from the event types.\n6. Click Save to create the webhook.\n\n**Note:** Webhooks are only available for paid subscriptions.\n ": "\nTo use this trigger, you need to manually set up a webhook in your Greip account:\n\n1. Login to your Greip dashboard.\n2. Go to Settings > Integrations > Webhooks.\n3. Click on \"Add Webhook\" or \"Create New Webhook\".\n4. Add the following URL in the **Webhook URL** field:\n```text\n{{webhookUrl}}\n```\n5. Select **proxy_detected** from the event types.\n6. Click Save to create the webhook.\n\n**Note:** Webhooks are only available for paid subscriptions.\n ",
"\nTo use this trigger, you need to manually set up a webhook in your Greip account:\n\n1. Login to your Greip dashboard.\n2. Go to Settings > Integrations > Webhooks.\n3. Click on \"Add Webhook\" or \"Create New Webhook\".\n4. Add the following URL in the **Webhook URL** field:\n```text\n{{webhookUrl}}\n```\n5. Select **fraud_payment** from the event types.\n6. Click Save to create the webhook.\n\n**Note:** Webhooks are only available for paid subscriptions.\n ": "\nTo use this trigger, you need to manually set up a webhook in your Greip account:\n\n1. Login to your Greip dashboard.\n2. Go to Settings > Integrations > Webhooks.\n3. Click on \"Add Webhook\" or \"Create New Webhook\".\n4. Add the following URL in the **Webhook URL** field:\n```text\n{{webhookUrl}}\n```\n5. Select **fraud_payment** from the event types.\n6. Click Save to create the webhook.\n\n**Note:** Webhooks are only available for paid subscriptions.\n ",
"\nTo use this trigger, you need to manually set up a webhook in your Greip account:\n\n1. Login to your Greip dashboard.\n2. Go to Settings > Integrations > Webhooks.\n3. Click on \"Add Webhook\" or \"Create New Webhook\".\n4. Add the following URL in the **Webhook URL** field:\n```text\n{{webhookUrl}}\n```\n5. Select **profanity** from the event types.\n6. Click Save to create the webhook.\n\n**Note:** Webhooks are only available for paid subscriptions.\n ": "\nTo use this trigger, you need to manually set up a webhook in your Greip account:\n\n1. Login to your Greip dashboard.\n2. Go to Settings > Integrations > Webhooks.\n3. Click on \"Add Webhook\" or \"Create New Webhook\".\n4. Add the following URL in the **Webhook URL** field:\n```text\n{{webhookUrl}}\n```\n5. Select **profanity** from the event types.\n6. Click Save to create the webhook.\n\n**Note:** Webhooks are only available for paid subscriptions.\n ",
"\nTo use this trigger, you need to manually set up a webhook in your Greip account:\n\n1. Login to your Greip dashboard.\n2. Go to Settings > Integrations > Webhooks.\n3. Click on \"Add Webhook\" or \"Create New Webhook\".\n4. Add the following URL in the **Webhook URL** field:\n```text\n{{webhookUrl}}\n```\n5. Select **spam_email** from the event types.\n6. Click Save to create the webhook.\n\n**Note:** Webhooks are only available for paid subscriptions.\n ": "\nTo use this trigger, you need to manually set up a webhook in your Greip account:\n\n1. Login to your Greip dashboard.\n2. Go to Settings > Integrations > Webhooks.\n3. Click on \"Add Webhook\" or \"Create New Webhook\".\n4. Add the following URL in the **Webhook URL** field:\n```text\n{{webhookUrl}}\n```\n5. Select **spam_email** from the event types.\n6. Click Save to create the webhook.\n\n**Note:** Webhooks are only available for paid subscriptions.\n ",
"\nTo use this trigger, you need to manually set up a webhook in your Greip account:\n\n1. Login to your Greip dashboard.\n2. Go to Settings > Integrations > Webhooks.\n3. Click on \"Add Webhook\" or \"Create New Webhook\".\n4. Add the following URL in the **Webhook URL** field:\n```text\n{{webhookUrl}}\n```\n5. Select **spam_phone** from the event types.\n6. Click Save to create the webhook.\n\n**Note:** Webhooks are only available for paid subscriptions.\n ": "\nTo use this trigger, you need to manually set up a webhook in your Greip account:\n\n1. Login to your Greip dashboard.\n2. Go to Settings > Integrations > Webhooks.\n3. Click on \"Add Webhook\" or \"Create New Webhook\".\n4. Add the following URL in the **Webhook URL** field:\n```text\n{{webhookUrl}}\n```\n5. Select **spam_phone** from the event types.\n6. Click Save to create the webhook.\n\n**Note:** Webhooks are only available for paid subscriptions.\n "
}

View File

@@ -0,0 +1,32 @@
import { createPiece } from '@activepieces/pieces-framework';
import { PieceCategory } from '@activepieces/shared';
import { greipAuth } from './lib/common/auth';
import { asnLookup } from './lib/actions/asn-lookup';
import { binLookup } from './lib/actions/bin-lookup';
import { ipLookup } from './lib/actions/ip-lookup';
import { emailValidation } from './lib/actions/email-validation';
import { profanityDetection } from './lib/actions/profanity-detection';
import { phoneValidation } from './lib/actions/phone-validation';
import { proxyConnectionDetectedTrigger } from './lib/triggers/proxy-connection-detected';
import { fraudulentPaymentDetectedTrigger } from './lib/triggers/fraudulent-payment-detected';
import { profanityTextDetectedTrigger } from './lib/triggers/profanity-text-detected';
import { spamEmailDetectedTrigger } from './lib/triggers/spam-email-detected';
import { spamPhoneDetectedTrigger } from './lib/triggers/spam-phone-detected';
export const greip = createPiece({
displayName: 'Greip',
description: 'Detect and prevent fraud in your website or app with Greip\'s Fraud Prevention API. Protect your business from financial losses and gain better insights into your users.',
auth: greipAuth,
minimumSupportedRelease: '0.36.1',
logoUrl: 'https://cdn.activepieces.com/pieces/greip.png',
categories: [PieceCategory.DEVELOPER_TOOLS],
authors: ["onyedikachi-david"],
actions: [asnLookup, binLookup, ipLookup, emailValidation, profanityDetection, phoneValidation],
triggers: [
proxyConnectionDetectedTrigger,
fraudulentPaymentDetectedTrigger,
profanityTextDetectedTrigger,
spamEmailDetectedTrigger,
spamPhoneDetectedTrigger,
],
});

View File

@@ -0,0 +1,76 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { HttpMethod } from '@activepieces/pieces-common';
import { greipAuth } from '../common/auth';
import { greipApiCall } from '../common/client';
export const asnLookup = createAction({
auth: greipAuth,
name: 'asn_lookup',
displayName: 'ASN Lookup',
description: 'Look up details of an Autonomous System Number (ASN)',
props: {
asn: Property.ShortText({
displayName: 'AS Number',
description: 'The AS Number to lookup (e.g., AS6167 or 6167)',
required: true,
}),
format: Property.StaticDropdown({
displayName: 'Response Format',
description: 'Format of the response',
required: false,
defaultValue: 'JSON',
options: {
options: [
{ label: 'JSON', value: 'JSON' },
{ label: 'XML', value: 'XML' },
{ label: 'CSV', value: 'CSV' },
{ label: 'Newline', value: 'Newline' },
],
},
}),
mode: Property.StaticDropdown({
displayName: 'Environment',
description: 'Environment mode for testing or production',
required: false,
defaultValue: 'live',
options: {
options: [
{ label: 'Live', value: 'live' },
{ label: 'Test', value: 'test' },
],
},
}),
callback: Property.ShortText({
displayName: 'JSONP Callback',
description: 'Function name for JSONP response format',
required: false,
}),
},
async run(context) {
const { asn, format, mode, callback } = context.propsValue;
const queryParams: Record<string, string> = {
asn: asn,
};
if (format) {
queryParams['format'] = format;
}
if (mode) {
queryParams['mode'] = mode;
}
if (callback) {
queryParams['callback'] = callback;
}
return await greipApiCall({
method: HttpMethod.GET,
path: '/lookup/asn',
queryParams,
auth: context.auth,
});
},
});

View File

@@ -0,0 +1,85 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { HttpMethod } from '@activepieces/pieces-common';
import { greipAuth } from '../common/auth';
import { greipApiCall } from '../common/client';
export const binLookup = createAction({
auth: greipAuth,
name: 'bin_lookup',
displayName: 'BIN Lookup',
description: 'Look up details of a Bank Identification Number (BIN) or Issuer Identification Number (IIN)',
props: {
bin: Property.ShortText({
displayName: 'BIN/IIN',
description: 'The BIN/IIN of the card (minimum 6 digits). Can be partial like "456789" or full card number',
required: true,
}),
format: Property.StaticDropdown({
displayName: 'Response Format',
description: 'Format of the response',
required: false,
defaultValue: 'JSON',
options: {
options: [
{ label: 'JSON', value: 'JSON' },
{ label: 'XML', value: 'XML' },
{ label: 'CSV', value: 'CSV' },
{ label: 'Newline', value: 'Newline' },
],
},
}),
mode: Property.StaticDropdown({
displayName: 'Environment',
description: 'Environment mode for testing or production',
required: false,
defaultValue: 'live',
options: {
options: [
{ label: 'Live', value: 'live' },
{ label: 'Test', value: 'test' },
],
},
}),
userID: Property.ShortText({
displayName: 'User Identifier',
description: 'Identify requests from specific users for monitoring (e.g., email, phone, user ID)',
required: false,
}),
callback: Property.ShortText({
displayName: 'JSONP Callback',
description: 'Function name for JSONP response format',
required: false,
}),
},
async run(context) {
const { bin, format, mode, userID, callback } = context.propsValue;
const queryParams: Record<string, string> = {
bin: bin,
};
if (format) {
queryParams['format'] = format;
}
if (mode) {
queryParams['mode'] = mode;
}
if (userID) {
queryParams['userID'] = userID;
}
if (callback) {
queryParams['callback'] = callback;
}
return await greipApiCall({
method: HttpMethod.GET,
path: '/lookup/bin',
queryParams,
auth: context.auth,
});
},
});

View File

@@ -0,0 +1,85 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { HttpMethod } from '@activepieces/pieces-common';
import { greipAuth } from '../common/auth';
import { greipApiCall } from '../common/client';
export const emailValidation = createAction({
auth: greipAuth,
name: 'email_validation',
displayName: 'Email Validation',
description: 'Validate email addresses by checking domain validity, detecting disposable emails, and assessing risk factors',
props: {
email: Property.ShortText({
displayName: 'Email Address',
description: 'The email address to validate',
required: true,
}),
format: Property.StaticDropdown({
displayName: 'Response Format',
description: 'Format of the response',
required: false,
defaultValue: 'JSON',
options: {
options: [
{ label: 'JSON', value: 'JSON' },
{ label: 'XML', value: 'XML' },
{ label: 'CSV', value: 'CSV' },
{ label: 'Newline', value: 'Newline' },
],
},
}),
mode: Property.StaticDropdown({
displayName: 'Environment',
description: 'Environment mode for testing or production',
required: false,
defaultValue: 'live',
options: {
options: [
{ label: 'Live', value: 'live' },
{ label: 'Test', value: 'test' },
],
},
}),
userID: Property.ShortText({
displayName: 'User Identifier',
description: 'Identify requests from specific users for monitoring (e.g., email, phone, user ID)',
required: false,
}),
callback: Property.ShortText({
displayName: 'JSONP Callback',
description: 'Function name for JSONP response format',
required: false,
}),
},
async run(context) {
const { email, format, mode, userID, callback } = context.propsValue;
const queryParams: Record<string, string> = {
email: email,
};
if (format) {
queryParams['format'] = format;
}
if (mode) {
queryParams['mode'] = mode;
}
if (userID) {
queryParams['userID'] = userID;
}
if (callback) {
queryParams['callback'] = callback;
}
return await greipApiCall({
method: HttpMethod.GET,
path: '/scoring/email',
queryParams,
auth: context.auth,
});
},
});

View File

@@ -0,0 +1,116 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { HttpMethod } from '@activepieces/pieces-common';
import { greipAuth } from '../common/auth';
import { greipApiCall } from '../common/client';
export const ipLookup = createAction({
auth: greipAuth,
name: 'ip_lookup',
displayName: 'IP Lookup',
description: 'Look up comprehensive information about an IP address including location, ISP, security, and risk factors',
props: {
ip: Property.ShortText({
displayName: 'IP Address',
description: 'The IP address to lookup (IPv4 or IPv6)',
required: true,
}),
params: Property.ShortText({
displayName: 'Modules',
description: 'Comma-separated list of modules to include: security, currency, timezone, location (e.g., "security,timezone,currency")',
required: false,
}),
format: Property.StaticDropdown({
displayName: 'Response Format',
description: 'Format of the response',
required: false,
defaultValue: 'JSON',
options: {
options: [
{ label: 'JSON', value: 'JSON' },
{ label: 'XML', value: 'XML' },
{ label: 'CSV', value: 'CSV' },
{ label: 'Newline', value: 'Newline' },
],
},
}),
lang: Property.StaticDropdown({
displayName: 'Response Language',
description: 'Language for the response',
required: false,
defaultValue: 'EN',
options: {
options: [
{ label: 'English', value: 'EN' },
{ label: 'Arabic', value: 'AR' },
{ label: 'German', value: 'DE' },
{ label: 'French', value: 'FR' },
{ label: 'Spanish', value: 'ES' },
{ label: 'Japanese', value: 'JA' },
{ label: 'Chinese', value: 'ZH' },
{ label: 'Russian', value: 'RU' },
],
},
}),
mode: Property.StaticDropdown({
displayName: 'Environment',
description: 'Environment mode for testing or production',
required: false,
defaultValue: 'live',
options: {
options: [
{ label: 'Live', value: 'live' },
{ label: 'Test', value: 'test' },
],
},
}),
userID: Property.ShortText({
displayName: 'User Identifier',
description: 'Identify requests from specific users for monitoring (e.g., email, phone, user ID)',
required: false,
}),
callback: Property.ShortText({
displayName: 'JSONP Callback',
description: 'Function name for JSONP response format',
required: false,
}),
},
async run(context) {
const { ip, params, format, lang, mode, userID, callback } = context.propsValue;
const queryParams: Record<string, string> = {
ip: ip,
};
if (params) {
queryParams['params'] = params;
}
if (format) {
queryParams['format'] = format;
}
if (lang) {
queryParams['lang'] = lang;
}
if (mode) {
queryParams['mode'] = mode;
}
if (userID) {
queryParams['userID'] = userID;
}
if (callback) {
queryParams['callback'] = callback;
}
return await greipApiCall({
method: HttpMethod.GET,
path: '/lookup/ip',
queryParams,
auth: context.auth,
});
},
});

View File

@@ -0,0 +1,91 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { HttpMethod } from '@activepieces/pieces-common';
import { greipAuth } from '../common/auth';
import { greipApiCall } from '../common/client';
export const phoneValidation = createAction({
auth: greipAuth,
name: 'phone_validation',
displayName: 'Phone Validation',
description: 'Validate phone numbers by checking syntax and assessing validity and operational status',
props: {
phone: Property.ShortText({
displayName: 'Phone Number',
description: 'The phone number to validate (e.g., +12121234567, 0012121234567, 12121234567, or 2121234567)',
required: true,
}),
countryCode: Property.ShortText({
displayName: 'Country Code',
description: 'ISO 3166-1 alpha-2 country code (e.g., US, GB, FR)',
required: true,
}),
format: Property.StaticDropdown({
displayName: 'Response Format',
description: 'Format of the response',
required: false,
defaultValue: 'JSON',
options: {
options: [
{ label: 'JSON', value: 'JSON' },
{ label: 'XML', value: 'XML' },
{ label: 'CSV', value: 'CSV' },
{ label: 'Newline', value: 'Newline' },
],
},
}),
mode: Property.StaticDropdown({
displayName: 'Environment',
description: 'Environment mode for testing or production',
required: false,
defaultValue: 'live',
options: {
options: [
{ label: 'Live', value: 'live' },
{ label: 'Test', value: 'test' },
],
},
}),
userID: Property.ShortText({
displayName: 'User Identifier',
description: 'Identify requests from specific users for monitoring (e.g., email, phone, user ID)',
required: false,
}),
callback: Property.ShortText({
displayName: 'JSONP Callback',
description: 'Function name for JSONP response format',
required: false,
}),
},
async run(context) {
const { phone, countryCode, format, mode, userID, callback } = context.propsValue;
const queryParams: Record<string, string> = {
phone: phone,
countryCode: countryCode,
};
if (format) {
queryParams['format'] = format;
}
if (mode) {
queryParams['mode'] = mode;
}
if (userID) {
queryParams['userID'] = userID;
}
if (callback) {
queryParams['callback'] = callback;
}
return await greipApiCall({
method: HttpMethod.GET,
path: '/scoring/phone',
queryParams,
auth: context.auth,
});
},
});

View File

@@ -0,0 +1,107 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { HttpMethod } from '@activepieces/pieces-common';
import { greipAuth } from '../common/auth';
import { greipApiCall } from '../common/client';
export const profanityDetection = createAction({
auth: greipAuth,
name: 'profanity_detection',
displayName: 'Detect Profanity',
description: 'Detect offensive or inappropriate language in text using machine learning',
props: {
text: Property.LongText({
displayName: 'Text',
description: 'The text to check for profanity',
required: true,
}),
scoreOnly: Property.StaticDropdown({
displayName: 'Score Only',
description: 'Return only the score and safety status',
required: false,
defaultValue: 'no',
options: {
options: [
{ label: 'No', value: 'no' },
{ label: 'Yes', value: 'yes' },
],
},
}),
listBadWords: Property.StaticDropdown({
displayName: 'List Bad Words',
description: 'Include a list of bad words found in the text',
required: false,
defaultValue: 'no',
options: {
options: [
{ label: 'No', value: 'no' },
{ label: 'Yes', value: 'yes' },
],
},
}),
format: Property.StaticDropdown({
displayName: 'Response Format',
description: 'Format of the response',
required: false,
defaultValue: 'JSON',
options: {
options: [
{ label: 'JSON', value: 'JSON' },
{ label: 'XML', value: 'XML' },
{ label: 'CSV', value: 'CSV' },
],
},
}),
mode: Property.StaticDropdown({
displayName: 'Environment',
description: 'Environment mode for testing or production',
required: false,
defaultValue: 'live',
options: {
options: [
{ label: 'Live', value: 'live' },
{ label: 'Test', value: 'test' },
],
},
}),
callback: Property.ShortText({
displayName: 'JSONP Callback',
description: 'Function name for JSONP response format',
required: false,
}),
},
async run(context) {
const { text, scoreOnly, listBadWords, format, mode, callback } = context.propsValue;
const queryParams: Record<string, string> = {
text: text,
};
if (scoreOnly) {
queryParams['scoreOnly'] = scoreOnly;
}
if (listBadWords) {
queryParams['listBadWords'] = listBadWords;
}
if (format) {
queryParams['format'] = format;
}
if (mode) {
queryParams['mode'] = mode;
}
if (callback) {
queryParams['callback'] = callback;
}
return await greipApiCall({
method: HttpMethod.GET,
path: '/scoring/profanity',
queryParams,
auth: context.auth,
});
},
});

View File

@@ -0,0 +1,53 @@
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
import { PieceAuth } from '@activepieces/pieces-framework';
const BASE_URL = 'https://greipapi.com';
export const greipAuth = PieceAuth.SecretText({
displayName: 'API Key',
description: `
To get your API Key:
1. Go to your Greip account dashboard
2. Navigate to API settings
3. Copy your API key
4. Paste it here
`,
required: true,
validate: async ({ auth }) => {
if (!auth) {
return {
valid: false,
error: 'API key is required',
};
}
try {
const response = await httpClient.sendRequest({
method: HttpMethod.GET,
url: `${BASE_URL}/geoip`,
headers: {
Authorization: `Bearer ${auth}`,
'Content-Type': 'application/json',
},
});
if (response.status === 200) {
return {
valid: true,
};
}
return {
valid: false,
error: 'Invalid API key',
};
} catch (error: any) {
return {
valid: false,
error: 'Invalid API key. Please check your API key and try again.',
};
}
},
});

View File

@@ -0,0 +1,143 @@
import { HttpMethod, httpClient, HttpMessageBody, QueryParams } from '@activepieces/pieces-common';
import { AppConnectionValueForAuthProperty, PiecePropValueSchema } from '@activepieces/pieces-framework';
import { greipAuth } from './auth';
const BASE_URL = 'https://greipapi.com';
export type GreipApiCallParams = {
method: HttpMethod;
path: string;
queryParams?: Record<string, string | number | string[] | undefined>;
body?: any;
auth: AppConnectionValueForAuthProperty<typeof greipAuth>;
};
export async function greipApiCall<T extends HttpMessageBody>({
method,
path,
queryParams,
body,
auth,
}: GreipApiCallParams): Promise<T> {
const url = `${BASE_URL}${path}`;
const headers: Record<string, string> = {
Authorization: `Bearer ${auth.secret_text}`,
'Content-Type': 'application/json',
};
const qs: QueryParams = {};
if (queryParams) {
for (const [key, value] of Object.entries(queryParams)) {
if (value !== null && value !== undefined) {
qs[key] = String(value);
}
}
}
try {
const response = await httpClient.sendRequest<T>({
method,
url,
headers,
queryParams: qs,
body,
});
// Check if response body indicates an error
if (response.body && typeof response.body === 'object' && 'status' in response.body && response.body.status === 'error') {
const errorBody = response.body as { code?: number; type?: string; description?: string };
throw new Error(errorBody.description || `Greip API error (code: ${errorBody.code || 'unknown'})`);
}
return response.body;
} catch (error: any) {
// Handle Greip API error response structure
let errorBody = error.response?.body || error.body;
// Handle stringified JSON error bodies
if (typeof errorBody === 'string') {
try {
errorBody = JSON.parse(errorBody);
} catch {
// If parsing fails, use the string as-is
}
}
// Check if it's a Greip error response
if (errorBody && typeof errorBody === 'object') {
// Check for nested error structure (error.response.body)
if (errorBody.response?.body) {
errorBody = errorBody.response.body;
}
if ('status' in errorBody && errorBody.status === 'error') {
const greipError = errorBody as { code?: number; type?: string; description?: string };
const description = greipError.description || getErrorMessageByCode(greipError.code);
throw new Error(description || `Greip API error (code: ${greipError.code || 'unknown'})`);
}
// Also check for description directly in errorBody
if ('description' in errorBody && errorBody.description) {
throw new Error(String(errorBody.description));
}
}
const statusCode = error.response?.status || error.status;
if (statusCode === 401 || statusCode === 403) {
throw new Error('Authentication failed. Please check your API key.');
}
if (statusCode === 429) {
throw new Error('Rate limit exceeded. Please wait a moment and try again.');
}
if (statusCode === 404) {
throw new Error('Endpoint not found. Please check the API endpoint path.');
}
if (statusCode >= 400 && statusCode < 500) {
const errorMessage = errorBody?.description || errorBody?.message || errorBody?.error || error.message || 'Request failed';
throw new Error(`Request failed: ${errorMessage}`);
}
// Fallback: include original error message if available
const originalMessage = error.message || String(error);
throw new Error(`Greip API error: ${originalMessage}`);
}
}
function getErrorMessageByCode(code?: number): string {
const errorMessages: Record<number, string> = {
101: 'The API Key is missing or invalid.',
102: 'The API Key owner account is inactive. Please contact support.',
103: 'You reached the usage limit of your account. Please upgrade your subscription.',
104: 'Invalid parameters. Please check the parameter values.',
105: 'Your plan has expired. Renew the subscription to enable using the API.',
106: 'Too many requests detected. Please slow down your request rate.',
107: 'The callback parameter value cannot be a function name.',
108: 'Invalid format. Use JSON, XML, CSV, or Newline.',
109: 'Callback feature can only be used with JSON format.',
110: 'Invalid language. Use EN, AR, FR, DE, ES, JA, ZH, or RU.',
111: 'Invalid mode. Use test or live.',
112: 'The IP Address is not valid or empty.',
113: 'Request sent from a domain that is not whitelisted in your API settings.',
114: 'Security module is not available in the free plan. Please upgrade.',
115: 'An error occurred while processing your request. Please try again later.',
116: 'The Country Code is invalid or not found.',
117: 'This feature is not available for your plan. Please upgrade.',
118: 'The Phone Number is invalid or missing.',
119: 'The Email Address is invalid or missing.',
120: 'The BIN number is invalid or missing.',
121: 'The AS Number is empty or invalid.',
122: 'The IBAN is invalid or missing.',
123: 'The user identifier is invalid or too long.',
124: 'The user type is invalid or missing. Use email, phone, or user_id.',
125: 'The user value is invalid or missing.',
126: 'You have reached the limit of deletions for this day. Please wait until the next day.',
};
return errorMessages[code || 0] || 'An unknown error occurred.';
}

View File

@@ -0,0 +1,62 @@
import {
createTrigger,
Property,
TriggerStrategy,
} from '@activepieces/pieces-framework';
import { greipAuth } from '../common/auth';
export const fraudulentPaymentDetectedTrigger = createTrigger({
name: 'fraudulent_payment_detected',
displayName: 'Fraudulent Payment Detected',
description: 'Triggers when a new fraudulent payment is detected by Greip',
auth: greipAuth,
props: {
webhookInstructions: Property.MarkDown({
value: `
To use this trigger, you need to manually set up a webhook in your Greip account:
1. Login to your Greip dashboard.
2. Go to Settings > Integrations > Webhooks.
3. Click on "Add Webhook" or "Create New Webhook".
4. Add the following URL in the **Webhook URL** field:
\`\`\`text
{{webhookUrl}}
\`\`\`
5. Select **fraud_payment** from the event types.
6. Click Save to create the webhook.
**Note:** Webhooks are only available for paid subscriptions.
`,
}),
},
type: TriggerStrategy.WEBHOOK,
sampleData: {
event: 'fraud_payment',
customer_id: 'UID123',
customer_email: 'name@domain.com',
customer_phone: '0555123456',
score: 31.666666666666664,
rules: [
{
id: 'PF10001',
description: 'High purchase rate, according to `customer_ip`.',
},
{
id: 'PF10002',
description: 'High purchase rate, according to `customer_id`.',
},
],
rulesChecked: 6,
rulesDetected: 2,
},
async onEnable(context) {
// Webhooks are set up manually in Greip dashboard
},
async onDisable(context) {
// Webhooks are removed manually in Greip dashboard
},
async run(context) {
return [context.payload.body];
},
});

View File

@@ -0,0 +1,50 @@
import {
createTrigger,
Property,
TriggerStrategy,
} from '@activepieces/pieces-framework';
import { greipAuth } from '../common/auth';
export const profanityTextDetectedTrigger = createTrigger({
name: 'profanity_text_detected',
displayName: 'Profanity Text Detected',
description: 'Triggers when Greip detects profanity in a specific text',
auth: greipAuth,
props: {
webhookInstructions: Property.MarkDown({
value: `
To use this trigger, you need to manually set up a webhook in your Greip account:
1. Login to your Greip dashboard.
2. Go to Settings > Integrations > Webhooks.
3. Click on "Add Webhook" or "Create New Webhook".
4. Add the following URL in the **Webhook URL** field:
\`\`\`text
{{webhookUrl}}
\`\`\`
5. Select **profanity** from the event types.
6. Click Save to create the webhook.
**Note:** Webhooks are only available for paid subscriptions.
`,
}),
},
type: TriggerStrategy.WEBHOOK,
sampleData: {
event: 'profanity',
text: '**** *****',
totalBadWords: 2,
riskScore: 1,
isSafe: false,
},
async onEnable(context) {
// Webhooks are set up manually in Greip dashboard
},
async onDisable(context) {
// Webhooks are removed manually in Greip dashboard
},
async run(context) {
return [context.payload.body];
},
});

View File

@@ -0,0 +1,60 @@
import {
createTrigger,
Property,
TriggerStrategy,
} from '@activepieces/pieces-framework';
import { greipAuth } from '../common/auth';
export const proxyConnectionDetectedTrigger = createTrigger({
name: 'proxy_connection_detected',
displayName: 'Proxy Connection Detected',
description: 'Triggers when a new proxy connection is detected',
auth: greipAuth,
props: {
webhookInstructions: Property.MarkDown({
value: `
To use this trigger, you need to manually set up a webhook in your Greip account:
1. Login to your Greip dashboard.
2. Go to Settings > Integrations > Webhooks.
3. Click on "Add Webhook" or "Create New Webhook".
4. Add the following URL in the **Webhook URL** field:
\`\`\`text
{{webhookUrl}}
\`\`\`
5. Select **proxy_detected** from the event types.
6. Click Save to create the webhook.
**Note:** Webhooks are only available for paid subscriptions.
`,
}),
},
type: TriggerStrategy.WEBHOOK,
sampleData: {
event: 'proxy_detected',
ip: '1.1.1.1',
ipType: 'IPv4',
IPNumber: 16843009,
countryCode: 'US',
countryGeoNameID: 6252001,
countryName: 'United States',
security: {
isProxy: false,
proxyType: null,
isTor: false,
isBot: false,
isRelay: false,
isHosting: false,
},
},
async onEnable(context) {
// Webhooks are set up manually in Greip dashboard
},
async onDisable(context) {
// Webhooks are removed manually in Greip dashboard
},
async run(context) {
return [context.payload.body];
},
});

View File

@@ -0,0 +1,50 @@
import {
createTrigger,
Property,
TriggerStrategy,
} from '@activepieces/pieces-framework';
import { greipAuth } from '../common/auth';
export const spamEmailDetectedTrigger = createTrigger({
name: 'spam_email_detected',
displayName: 'Spam Email Detected',
description: 'Triggers when a new email is marked as SPAM by Greip',
auth: greipAuth,
props: {
webhookInstructions: Property.MarkDown({
value: `
To use this trigger, you need to manually set up a webhook in your Greip account:
1. Login to your Greip dashboard.
2. Go to Settings > Integrations > Webhooks.
3. Click on "Add Webhook" or "Create New Webhook".
4. Add the following URL in the **Webhook URL** field:
\`\`\`text
{{webhookUrl}}
\`\`\`
5. Select **spam_email** from the event types.
6. Click Save to create the webhook.
**Note:** Webhooks are only available for paid subscriptions.
`,
}),
},
type: TriggerStrategy.WEBHOOK,
sampleData: {
event: 'spam_email',
email: 'name@domain.com',
score: 3,
reason: 'Email domain\'s SPF record is not set properly.',
isValid: false,
},
async onEnable(context) {
// Webhooks are set up manually in Greip dashboard
},
async onDisable(context) {
// Webhooks are removed manually in Greip dashboard
},
async run(context) {
return [context.payload.body];
},
});

View File

@@ -0,0 +1,51 @@
import {
createTrigger,
Property,
TriggerStrategy,
} from '@activepieces/pieces-framework';
import { greipAuth } from '../common/auth';
export const spamPhoneDetectedTrigger = createTrigger({
name: 'spam_phone_detected',
displayName: 'Spam Phone Number Detected',
description: 'Triggers when a new phone number is marked as SPAM by Greip',
auth: greipAuth,
props: {
webhookInstructions: Property.MarkDown({
value: `
To use this trigger, you need to manually set up a webhook in your Greip account:
1. Login to your Greip dashboard.
2. Go to Settings > Integrations > Webhooks.
3. Click on "Add Webhook" or "Create New Webhook".
4. Add the following URL in the **Webhook URL** field:
\`\`\`text
{{webhookUrl}}
\`\`\`
5. Select **spam_phone** from the event types.
6. Click Save to create the webhook.
**Note:** Webhooks are only available for paid subscriptions.
`,
}),
},
type: TriggerStrategy.WEBHOOK,
sampleData: {
event: 'spam_phone',
phone: '0555123456',
countryCode: 'ir',
carrier: '',
reason: 'Invalid phone number structure.',
isValid: false,
},
async onEnable(context) {
// Webhooks are set up manually in Greip dashboard
},
async onDisable(context) {
// Webhooks are removed manually in Greip dashboard
},
async run(context) {
return [context.payload.body];
},
});

View File

@@ -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"
}
]
}

View File

@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../../dist/out-tsc",
"declaration": true,
"types": ["node"]
},
"include": ["src/**/*.ts"]
}