Edits history of script submission #22240 for ' Create Actor Webhook (apify)'

  • bun
    One script reply has been approved by the moderators
    Ap­pro­ved
    import { ActorListSortBy, ApifyClient } from 'apify-client@^2.19.0';
    import { createHash } from 'node:crypto';
    
    type ApifyApiKey = {
      api_key: string;
    };
    
    type Apify = {
      token: string;
    };
    
    type WebhookEventTypes =
      | 'ACTOR.RUN.SUCCEEDED'
      | 'ACTOR.RUN.FAILED'
      | 'ACTOR.RUN.TIMED_OUT'
      | 'ACTOR.RUN.ABORTED'
    
    type ApifyWebhookConfig = {
      url: string;
      token: string;
    };
    
    type ActorSource = 'RECENTLY_USED_ACTORS' | 'APIFY_STORE_ACTORS';
    
    export type DynSelect_actorId = string;
    export async function actorId(actorSource: ActorSource, api_key?: ApifyApiKey, oauth_token?: Apify) {
      if (!api_key?.api_key && !oauth_token?.token) {
        return [{ value: '', label: 'Missing Apify API key or OAuth token' }];
      }
    
      const client = createClient(api_key, oauth_token);
    
      const mapActorToSelectOption = (actor: any) => {
        const optionName = actor.title
          ? `${actor.title} (${actor.username}/${actor.name})`
          : `${actor.username}/${actor.name}`;
    
        return {
          label: optionName,
          value: actor.id,
        };
      };
    
      try {
        if (actorSource === 'RECENTLY_USED_ACTORS') {
          const recentActors = await client.actors().list({
            limit: 100,
            offset: 0,
            sortBy: ActorListSortBy.LAST_RUN_STARTED_AT,
            desc: true,
          });
          return recentActors.items.map(mapActorToSelectOption);
        }
    
        const storeActors = await client.store().list({
          limit: 1000,
          offset: 0,
        });
        return storeActors.items.map(mapActorToSelectOption);
      } catch (error: any) {
        return [
          { value: '', label: `Failed to load actors: ${error.message || error}` },
        ];
      }
    }
    
    function prettifyEvent(e: string) {
      return e.replace(/^ACTOR\.RUN\./, '');
    }
    
    function generateIdempotencyKey(
      id: string,
      eventTypes: WebhookEventTypes[],
      requestUrl: string
    ): string {
      const sortedEventTypes = [...eventTypes].sort();
      const url = new URL(requestUrl);
      const pathname = url.pathname;
      const hash = createHash('sha256');
      hash.update(`${id}:${sortedEventTypes.join(',')}:${pathname}`);
      return hash.digest('hex');
    }
    
    const createClient = (api_key?: ApifyApiKey, oauth_token?: Apify): ApifyClient => {
      const token = oauth_token?.token ?? api_key?.api_key;
      if (!token) {
        throw new Error('Missing Apify API key or OAuth token');
      }
    
      return new ApifyClient({
        token: token,
        requestInterceptors: [
          (request) => {
            if (!request.headers) {
              request.headers = {};
            }
            request.headers['x-apify-integration-platform'] = 'windmill';
            return request;
          },
        ],
      });
    };
    
    export async function main(
      actorSource: ActorSource,
      apifyWebhookConfig: ApifyWebhookConfig,
      actorId: DynSelect_actorId,
      eventTypes: WebhookEventTypes[],
      api_key?: ApifyApiKey,
      oauth_token?: Apify,
    ) {
      if (!actorId) {
        return { error: 'Actor ID is required' };
      }
    
      const client = createClient(api_key, oauth_token);
    
      const idempotencyKey = generateIdempotencyKey(
        actorId,
        eventTypes,
        apifyWebhookConfig.url
      );
      const headersTemplate = JSON.stringify({
        Authorization: `Bearer ${apifyWebhookConfig.token}`,
      });
    
      // get actor to store name for later webhook deletion
      const actor = await client.actor(actorId).get();
      const actorName = actor && (actor.title || actor.name);
      const webhookEvents = eventTypes
        .map((event) => prettifyEvent(event))
        .join(', ');
    
      try {
        const response = await client.webhooks().create({
          requestUrl: apifyWebhookConfig.url,
          eventTypes: eventTypes,
          condition: {
            actorId: actorId,
          },
          idempotencyKey,
          headersTemplate,
          shouldInterpolateStrings: true,
          description: `${actorName}: ${webhookEvents}`,
          title: "Windmill integration"
        });
    
        return response;
      } catch (e: any) {
        return { error: `Failed to create a webhook. Reason: ${e.message}` };
      }
    }
    

    Submitted by jakub.drobnik222 172 days ago