diff --git a/packages/api/src/generated/graphql.ts b/packages/api/src/generated/graphql.ts index 7826942eb..52604d31a 100644 --- a/packages/api/src/generated/graphql.ts +++ b/packages/api/src/generated/graphql.ts @@ -892,6 +892,23 @@ export type EmptyTrashSuccess = { success?: Maybe; }; +export type ExportToIntegrationError = { + __typename?: 'ExportToIntegrationError'; + errorCodes: Array; +}; + +export enum ExportToIntegrationErrorCode { + FailedToCreateTask = 'FAILED_TO_CREATE_TASK', + Unauthorized = 'UNAUTHORIZED' +} + +export type ExportToIntegrationResult = ExportToIntegrationError | ExportToIntegrationSuccess; + +export type ExportToIntegrationSuccess = { + __typename?: 'ExportToIntegrationSuccess'; + task: Task; +}; + export type Feature = { __typename?: 'Feature'; createdAt: Scalars['Date']; @@ -1582,6 +1599,7 @@ export type Mutation = { deleteWebhook: DeleteWebhookResult; editDiscoverFeed: EditDiscoverFeedResult; emptyTrash: EmptyTrashResult; + exportToIntegration: ExportToIntegrationResult; fetchContent: FetchContentResult; generateApiKey: GenerateApiKeyResult; googleLogin: LoginResult; @@ -1737,6 +1755,11 @@ export type MutationEditDiscoverFeedArgs = { }; +export type MutationExportToIntegrationArgs = { + integrationId: Scalars['ID']; +}; + + export type MutationFetchContentArgs = { id: Scalars['ID']; }; @@ -3183,6 +3206,26 @@ export type SyncUpdatedItemEdge = { updateReason: UpdateReason; }; +export type Task = { + __typename?: 'Task'; + cancellable?: Maybe; + createdAt: Scalars['Date']; + failedReason?: Maybe; + id: Scalars['ID']; + name: Scalars['String']; + progress?: Maybe; + runningTime?: Maybe; + state: TaskState; +}; + +export enum TaskState { + Cancelled = 'CANCELLED', + Failed = 'FAILED', + Pending = 'PENDING', + Running = 'RUNNING', + Succeeded = 'SUCCEEDED' +} + export type TypeaheadSearchError = { __typename?: 'TypeaheadSearchError'; errorCodes: Array; @@ -4014,6 +4057,10 @@ export type ResolversTypes = { EmptyTrashErrorCode: EmptyTrashErrorCode; EmptyTrashResult: ResolversTypes['EmptyTrashError'] | ResolversTypes['EmptyTrashSuccess']; EmptyTrashSuccess: ResolverTypeWrapper; + ExportToIntegrationError: ResolverTypeWrapper; + ExportToIntegrationErrorCode: ExportToIntegrationErrorCode; + ExportToIntegrationResult: ResolversTypes['ExportToIntegrationError'] | ResolversTypes['ExportToIntegrationSuccess']; + ExportToIntegrationSuccess: ResolverTypeWrapper; Feature: ResolverTypeWrapper; Feed: ResolverTypeWrapper; FeedArticle: ResolverTypeWrapper; @@ -4323,6 +4370,8 @@ export type ResolversTypes = { SubscriptionsResult: ResolversTypes['SubscriptionsError'] | ResolversTypes['SubscriptionsSuccess']; SubscriptionsSuccess: ResolverTypeWrapper; SyncUpdatedItemEdge: ResolverTypeWrapper; + Task: ResolverTypeWrapper; + TaskState: TaskState; TypeaheadSearchError: ResolverTypeWrapper; TypeaheadSearchErrorCode: TypeaheadSearchErrorCode; TypeaheadSearchItem: ResolverTypeWrapper; @@ -4564,6 +4613,9 @@ export type ResolversParentTypes = { EmptyTrashError: EmptyTrashError; EmptyTrashResult: ResolversParentTypes['EmptyTrashError'] | ResolversParentTypes['EmptyTrashSuccess']; EmptyTrashSuccess: EmptyTrashSuccess; + ExportToIntegrationError: ExportToIntegrationError; + ExportToIntegrationResult: ResolversParentTypes['ExportToIntegrationError'] | ResolversParentTypes['ExportToIntegrationSuccess']; + ExportToIntegrationSuccess: ExportToIntegrationSuccess; Feature: Feature; Feed: Feed; FeedArticle: FeedArticle; @@ -4804,6 +4856,7 @@ export type ResolversParentTypes = { SubscriptionsResult: ResolversParentTypes['SubscriptionsError'] | ResolversParentTypes['SubscriptionsSuccess']; SubscriptionsSuccess: SubscriptionsSuccess; SyncUpdatedItemEdge: SyncUpdatedItemEdge; + Task: Task; TypeaheadSearchError: TypeaheadSearchError; TypeaheadSearchItem: TypeaheadSearchItem; TypeaheadSearchResult: ResolversParentTypes['TypeaheadSearchError'] | ResolversParentTypes['TypeaheadSearchSuccess']; @@ -5502,6 +5555,20 @@ export type EmptyTrashSuccessResolvers; }; +export type ExportToIntegrationErrorResolvers = { + errorCodes?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}; + +export type ExportToIntegrationResultResolvers = { + __resolveType: TypeResolveFn<'ExportToIntegrationError' | 'ExportToIntegrationSuccess', ParentType, ContextType>; +}; + +export type ExportToIntegrationSuccessResolvers = { + task?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}; + export type FeatureResolvers = { createdAt?: Resolver; expiresAt?: Resolver, ParentType, ContextType>; @@ -6037,6 +6104,7 @@ export type MutationResolvers>; editDiscoverFeed?: Resolver>; emptyTrash?: Resolver; + exportToIntegration?: Resolver>; fetchContent?: Resolver>; generateApiKey?: Resolver>; googleLogin?: Resolver>; @@ -6788,6 +6856,18 @@ export type SyncUpdatedItemEdgeResolvers; }; +export type TaskResolvers = { + cancellable?: Resolver, ParentType, ContextType>; + createdAt?: Resolver; + failedReason?: Resolver, ParentType, ContextType>; + id?: Resolver; + name?: Resolver; + progress?: Resolver, ParentType, ContextType>; + runningTime?: Resolver, ParentType, ContextType>; + state?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}; + export type TypeaheadSearchErrorResolvers = { errorCodes?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; @@ -7272,6 +7352,9 @@ export type Resolvers = { EmptyTrashError?: EmptyTrashErrorResolvers; EmptyTrashResult?: EmptyTrashResultResolvers; EmptyTrashSuccess?: EmptyTrashSuccessResolvers; + ExportToIntegrationError?: ExportToIntegrationErrorResolvers; + ExportToIntegrationResult?: ExportToIntegrationResultResolvers; + ExportToIntegrationSuccess?: ExportToIntegrationSuccessResolvers; Feature?: FeatureResolvers; Feed?: FeedResolvers; FeedArticle?: FeedArticleResolvers; @@ -7473,6 +7556,7 @@ export type Resolvers = { SubscriptionsResult?: SubscriptionsResultResolvers; SubscriptionsSuccess?: SubscriptionsSuccessResolvers; SyncUpdatedItemEdge?: SyncUpdatedItemEdgeResolvers; + Task?: TaskResolvers; TypeaheadSearchError?: TypeaheadSearchErrorResolvers; TypeaheadSearchItem?: TypeaheadSearchItemResolvers; TypeaheadSearchResult?: TypeaheadSearchResultResolvers; diff --git a/packages/api/src/generated/schema.graphql b/packages/api/src/generated/schema.graphql index 3316218ba..a7d51dcef 100644 --- a/packages/api/src/generated/schema.graphql +++ b/packages/api/src/generated/schema.graphql @@ -794,6 +794,21 @@ type EmptyTrashSuccess { success: Boolean } +type ExportToIntegrationError { + errorCodes: [ExportToIntegrationErrorCode!]! +} + +enum ExportToIntegrationErrorCode { + FAILED_TO_CREATE_TASK + UNAUTHORIZED +} + +union ExportToIntegrationResult = ExportToIntegrationError | ExportToIntegrationSuccess + +type ExportToIntegrationSuccess { + task: Task! +} + type Feature { createdAt: Date! expiresAt: Date @@ -1422,6 +1437,7 @@ type Mutation { deleteWebhook(id: ID!): DeleteWebhookResult! editDiscoverFeed(input: EditDiscoverFeedInput!): EditDiscoverFeedResult! emptyTrash: EmptyTrashResult! + exportToIntegration(integrationId: ID!): ExportToIntegrationResult! fetchContent(id: ID!): FetchContentResult! generateApiKey(input: GenerateApiKeyInput!): GenerateApiKeyResult! googleLogin(input: GoogleLoginInput!): LoginResult! @@ -2517,6 +2533,25 @@ type SyncUpdatedItemEdge { updateReason: UpdateReason! } +type Task { + cancellable: Boolean + createdAt: Date! + failedReason: String + id: ID! + name: String! + progress: Float + runningTime: Int + state: TaskState! +} + +enum TaskState { + CANCELLED + FAILED + PENDING + RUNNING + SUCCEEDED +} + type TypeaheadSearchError { errorCodes: [TypeaheadSearchErrorCode!]! } diff --git a/packages/api/src/queue-processor.ts b/packages/api/src/queue-processor.ts index 36bea979b..2e97a9686 100644 --- a/packages/api/src/queue-processor.ts +++ b/packages/api/src/queue-processor.ts @@ -5,6 +5,7 @@ import { ConnectionOptions, Job, + JobState, JobType, Queue, QueueEvents, @@ -13,6 +14,7 @@ import { import express, { Express } from 'express' import { appDataSource } from './data_source' import { env } from './env' +import { TaskState } from './generated/graphql' import { aiSummarize, AI_SUMMARIZE_JOB_NAME } from './jobs/ai-summarize' import { bulkAction, BULK_ACTION_JOB_NAME } from './jobs/bulk_action' import { callWebhook, CALL_WEBHOOK_JOB_NAME } from './jobs/call_webhook' @@ -25,6 +27,12 @@ import { exportItem, EXPORT_ITEM_JOB_NAME, } from './jobs/integration/export_item' +import { + processYouTubeTranscript, + processYouTubeVideo, + PROCESS_YOUTUBE_TRANSCRIPT_JOB_NAME, + PROCESS_YOUTUBE_VIDEO_JOB_NAME, +} from './jobs/process-youtube-video' import { refreshAllFeeds } from './jobs/rss/refreshAllFeeds' import { refreshFeed } from './jobs/rss/refreshFeed' import { savePageJob } from './jobs/save_page' @@ -44,12 +52,6 @@ import { redisDataSource } from './redis_data_source' import { CACHED_READING_POSITION_PREFIX } from './services/cached_reading_position' import { getJobPriority } from './utils/createTask' import { logger } from './utils/logger' -import { - PROCESS_YOUTUBE_TRANSCRIPT_JOB_NAME, - PROCESS_YOUTUBE_VIDEO_JOB_NAME, - processYouTubeTranscript, - processYouTubeVideo, -} from './jobs/process-youtube-video' export const QUEUE_NAME = 'omnivore-backend-queue' export const JOB_VERSION = 'v001' @@ -82,6 +84,33 @@ export const getBackendQueue = async (): Promise => { return backendQueue } +export const getJob = async (jobId: string) => { + const queue = await getBackendQueue() + if (!queue) { + return + } + return queue.getJob(jobId) +} + +export const jobStateToTaskState = ( + jobState: JobState | 'unknown' +): TaskState => { + switch (jobState) { + case 'completed': + return TaskState.Succeeded + case 'failed': + return TaskState.Failed + case 'active': + return TaskState.Running + case 'delayed': + return TaskState.Pending + case 'waiting': + return TaskState.Pending + default: + return TaskState.Pending + } +} + export const createWorker = (connection: ConnectionOptions) => new Worker( QUEUE_NAME, diff --git a/packages/api/src/resolvers/function_resolvers.ts b/packages/api/src/resolvers/function_resolvers.ts index c70f7145d..8757c10a1 100644 --- a/packages/api/src/resolvers/function_resolvers.ts +++ b/packages/api/src/resolvers/function_resolvers.ts @@ -41,6 +41,15 @@ import { generateUploadFilePathName, } from '../utils/uploads' import { emptyTrashResolver, fetchContentResolver } from './article' +import { + addDiscoverFeedResolver, + deleteDiscoverArticleResolver, + deleteDiscoverFeedsResolver, + editDiscoverFeedsResolver, + getDiscoverFeedArticlesResolver, + getDiscoverFeedsResolver, + saveDiscoverArticleResolver, +} from './discover_feeds' import { optInFeatureResolver } from './features' import { uploadImportFileResolver } from './importers/uploadImportFileResolver' import { @@ -65,6 +74,7 @@ import { deleteRuleResolver, deleteWebhookResolver, deviceTokensResolver, + exportToIntegrationResolver, feedsResolver, filtersResolver, generateApiKeyResolver, @@ -144,15 +154,6 @@ import { markEmailAsItemResolver, recentEmailsResolver } from './recent_emails' import { recentSearchesResolver } from './recent_searches' import { WithDataSourcesContext } from './types' import { updateEmailResolver } from './user' -import { - addDiscoverFeedResolver, - getDiscoverFeedsResolver, - getDiscoverFeedArticlesResolver, - saveDiscoverArticleResolver, - deleteDiscoverArticleResolver, - deleteDiscoverFeedsResolver, - editDiscoverFeedsResolver, -} from './discover_feeds' /* eslint-disable @typescript-eslint/naming-convention */ type ResultResolveType = { @@ -314,6 +315,7 @@ export const functionResolvers = { editDiscoverFeed: editDiscoverFeedsResolver, emptyTrash: emptyTrashResolver, fetchContent: fetchContentResolver, + exportToIntegration: exportToIntegrationResolver, }, Query: { me: getMeUserResolver, @@ -665,4 +667,5 @@ export const functionResolvers = { ...resultResolveTypeResolver('EmptyTrash'), ...resultResolveTypeResolver('FetchContent'), ...resultResolveTypeResolver('Integration'), + ...resultResolveTypeResolver('ExportToIntegration'), } diff --git a/packages/api/src/resolvers/integrations/index.ts b/packages/api/src/resolvers/integrations/index.ts index 0f186bc36..1e3388517 100644 --- a/packages/api/src/resolvers/integrations/index.ts +++ b/packages/api/src/resolvers/integrations/index.ts @@ -9,6 +9,9 @@ import { DeleteIntegrationError, DeleteIntegrationErrorCode, DeleteIntegrationSuccess, + ExportToIntegrationError, + ExportToIntegrationErrorCode, + ExportToIntegrationSuccess, ImportFromIntegrationError, ImportFromIntegrationErrorCode, ImportFromIntegrationSuccess, @@ -18,12 +21,14 @@ import { IntegrationsSuccess, IntegrationSuccess, MutationDeleteIntegrationArgs, + MutationExportToIntegrationArgs, MutationImportFromIntegrationArgs, MutationSetIntegrationArgs, QueryIntegrationArgs, SetIntegrationError, SetIntegrationErrorCode, SetIntegrationSuccess, + TaskState, } from '../../generated/graphql' import { createIntegrationToken } from '../../routers/auth/jwt_helpers' import { @@ -38,6 +43,7 @@ import { import { analytics } from '../../utils/analytics' import { deleteTask, + enqueueExportToIntegration, enqueueImportFromIntegration, } from '../../utils/createTask' import { authorized } from '../../utils/gql-utils' @@ -216,3 +222,52 @@ export const importFromIntegrationResolver = authorized< success: true, } }) + +export const exportToIntegrationResolver = authorized< + ExportToIntegrationSuccess, + ExportToIntegrationError, + MutationExportToIntegrationArgs +>(async (_, { integrationId }, { uid, log }) => { + const integration = await findIntegration({ id: integrationId }, uid) + + if (!integration) { + log.error('integration not found', integrationId) + + return { + errorCodes: [ExportToIntegrationErrorCode.Unauthorized], + } + } + + // create a job to export all the items + const job = await enqueueExportToIntegration(integration.id, uid) + if (!job || !job.id) { + log.error('failed to create task', integrationId) + + return { + errorCodes: [ExportToIntegrationErrorCode.FailedToCreateTask], + } + } + + // update task name in integration + await updateIntegration(integration.id, { taskName: job.id }, uid) + + analytics.capture({ + distinctId: uid, + event: 'integration_export', + properties: { + integrationId, + }, + }) + + return { + task: { + id: job.id, + name: job.name, + state: TaskState.Pending, + createdAt: new Date(job.timestamp), + progress: 0, + runningTime: 0, + cancellable: true, + }, + } +}) diff --git a/packages/api/src/routers/svc/integrations.ts b/packages/api/src/routers/svc/integrations.ts deleted file mode 100644 index b91bd4b20..000000000 --- a/packages/api/src/routers/svc/integrations.ts +++ /dev/null @@ -1,65 +0,0 @@ -/* eslint-disable @typescript-eslint/no-misused-promises */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import express from 'express' -import { Integration, IntegrationType } from '../../entity/integration' -import { readPushSubscription } from '../../pubsub' -import { getRepository } from '../../repository' -import { enqueueExportAllItems } from '../../utils/createTask' -import { logger } from '../../utils/logger' -import { createIntegrationToken } from '../auth/jwt_helpers' - -export function integrationsServiceRouter() { - const router = express.Router() - - router.post('/export', async (req, res) => { - logger.info('start to sync with integration') - - try { - const { message: msgStr, expired } = readPushSubscription(req) - if (!msgStr) { - return res.status(200).send('Bad Request') - } - - if (expired) { - logger.info('discarding expired message') - return res.status(200).send('Expired') - } - - // find all active integrations - const integrations = await getRepository(Integration).find({ - where: { - enabled: true, - type: IntegrationType.Export, - }, - relations: ['user'], - }) - - // create a task to sync with each integration - await Promise.all( - integrations.map(async (integration) => { - const authToken = await createIntegrationToken({ - uid: integration.user.id, - token: integration.token, - }) - - if (!authToken) { - logger.error('failed to create auth token', { - integrationId: integration.id, - }) - return - } - - return enqueueExportAllItems(integration.id, integration.user.id) - }) - ) - } catch (err) { - logger.error('sync with integrations failed', err) - return res.status(500).send(err) - } - - res.status(200).send('OK') - }) - - return router -} diff --git a/packages/api/src/routers/task_router.ts b/packages/api/src/routers/task_router.ts new file mode 100644 index 000000000..f6e50d026 --- /dev/null +++ b/packages/api/src/routers/task_router.ts @@ -0,0 +1,49 @@ +import cors from 'cors' +import express from 'express' +import { Task, TaskState } from '../generated/graphql' +import { getJob, jobStateToTaskState } from '../queue-processor' +import { getClaimsByToken, getTokenByRequest } from '../utils/auth' +import { corsConfig } from '../utils/corsConfig' +import { logger } from '../utils/logger' + +export function taskRouter() { + const router = express.Router() + + router.get('/:id', cors(corsConfig), async (req, res) => { + const token = getTokenByRequest(req) + const claims = await getClaimsByToken(token) + if (!claims) { + return res.status(401).send('UNAUTHORIZED') + } + + try { + const job = await getJob(req.params.id) + if (!job || !job.id) { + res.status(404).send('Not Found') + return + } + + const jobState = await job.getState() + const state = jobStateToTaskState(jobState) + const finishedAt = job.finishedOn ? job.finishedOn : Date.now() + const runningTime = job.processedOn ? finishedAt - job.processedOn : 0 + + const result: Task = { + id: job.id, + state, + createdAt: new Date(job.timestamp), + name: job.name, + runningTime, + progress: job.progress as number, + failedReason: state === TaskState.Failed ? job.failedReason : undefined, + } + + res.send(result) + } catch (e) { + logger.error('failed to get task', e) + res.status(500) + } + }) + + return router +} diff --git a/packages/api/src/schema.ts b/packages/api/src/schema.ts index 7819035ac..76c793dbd 100755 --- a/packages/api/src/schema.ts +++ b/packages/api/src/schema.ts @@ -3023,6 +3023,42 @@ const schema = gql` NOT_FOUND } + union ExportToIntegrationResult = + ExportToIntegrationSuccess + | ExportToIntegrationError + + type ExportToIntegrationSuccess { + task: Task! + } + + type Task { + id: ID! + name: String! + state: TaskState! + createdAt: Date! + runningTime: Int # in milliseconds + cancellable: Boolean + progress: Float + failedReason: String + } + + enum TaskState { + PENDING + RUNNING + SUCCEEDED + FAILED + CANCELLED + } + + type ExportToIntegrationError { + errorCodes: [ExportToIntegrationErrorCode!]! + } + + enum ExportToIntegrationErrorCode { + UNAUTHORIZED + FAILED_TO_CREATE_TASK + } + # Mutations type Mutation { googleLogin(input: GoogleLoginInput!): LoginResult! @@ -3131,6 +3167,7 @@ const schema = gql` arguments: JSON # additional arguments for the action ): BulkActionResult! importFromIntegration(integrationId: ID!): ImportFromIntegrationResult! + exportToIntegration(integrationId: ID!): ExportToIntegrationResult! setFavoriteArticle(id: ID!): SetFavoriteArticleResult! updateSubscription( input: UpdateSubscriptionInput! diff --git a/packages/api/src/server.ts b/packages/api/src/server.ts index 995f7f289..5199012f3 100755 --- a/packages/api/src/server.ts +++ b/packages/api/src/server.ts @@ -18,6 +18,7 @@ import { makeApolloServer } from './apollo' import { appDataSource } from './data_source' import { env } from './env' import { redisDataSource } from './redis_data_source' +import { aiSummariesRouter } from './routers/ai_summary_router' import { articleRouter } from './routers/article_router' import { authRouter } from './routers/auth/auth_router' import { mobileAuthRouter } from './routers/auth/mobile/mobile_auth_router' @@ -29,7 +30,6 @@ import { contentServiceRouter } from './routers/svc/content' import { emailsServiceRouter } from './routers/svc/emails' import { emailAttachmentRouter } from './routers/svc/email_attachment' import { followingServiceRouter } from './routers/svc/following' -import { integrationsServiceRouter } from './routers/svc/integrations' import { linkServiceRouter } from './routers/svc/links' import { newsletterServiceRouter } from './routers/svc/newsletters' // import { remindersServiceRouter } from './routers/svc/reminders' @@ -37,6 +37,7 @@ import { rssFeedRouter } from './routers/svc/rss_feed' import { uploadServiceRouter } from './routers/svc/upload' import { userServiceRouter } from './routers/svc/user' import { webhooksServiceRouter } from './routers/svc/webhooks' +import { taskRouter } from './routers/task_router' import { textToSpeechRouter } from './routers/text_to_speech' import { userRouter } from './routers/user_router' import { sentryConfig } from './sentry' @@ -48,7 +49,6 @@ import { } from './utils/auth' import { corsConfig } from './utils/corsConfig' import { buildLogger, buildLoggerTransport, logger } from './utils/logger' -import { aiSummariesRouter } from './routers/ai_summary_router' const PORT = process.env.PORT || 4000 @@ -126,13 +126,13 @@ export const createApp = (): { app.use('/api/text-to-speech', textToSpeechRouter()) app.use('/api/notification', notificationRouter()) app.use('/api/integration', integrationRouter()) + app.use('/api/tasks', taskRouter()) app.use('/svc/pubsub/content', contentServiceRouter()) app.use('/svc/pubsub/links', linkServiceRouter()) app.use('/svc/pubsub/newsletters', newsletterServiceRouter()) app.use('/svc/pubsub/emails', emailsServiceRouter()) app.use('/svc/pubsub/upload', uploadServiceRouter()) app.use('/svc/pubsub/webhooks', webhooksServiceRouter()) - app.use('/svc/pubsub/integrations', integrationsServiceRouter()) app.use('/svc/pubsub/rss-feed', rssFeedRouter()) app.use('/svc/pubsub/user', userServiceRouter()) // app.use('/svc/reminders', remindersServiceRouter()) diff --git a/packages/api/src/utils/createTask.ts b/packages/api/src/utils/createTask.ts index 6d6c30baf..39e99a6f3 100644 --- a/packages/api/src/utils/createTask.ts +++ b/packages/api/src/utils/createTask.ts @@ -15,6 +15,7 @@ import { ArticleSavingRequestStatus, CreateLabelInput, } from '../generated/graphql' +import { AISummarizeJobData, AI_SUMMARIZE_JOB_NAME } from '../jobs/ai-summarize' import { BulkActionData, BULK_ACTION_JOB_NAME } from '../jobs/bulk_action' import { CallWebhookJobData, CALL_WEBHOOK_JOB_NAME } from '../jobs/call_webhook' import { THUMBNAIL_JOB } from '../jobs/find_thumbnail' @@ -23,6 +24,12 @@ import { ExportItemJobData, EXPORT_ITEM_JOB_NAME, } from '../jobs/integration/export_item' +import { + ProcessYouTubeTranscriptJobData, + ProcessYouTubeVideoJobData, + PROCESS_YOUTUBE_TRANSCRIPT_JOB_NAME, + PROCESS_YOUTUBE_VIDEO_JOB_NAME, +} from '../jobs/process-youtube-video' import { queueRSSRefreshFeedJob, REFRESH_ALL_FEEDS_JOB_NAME, @@ -44,13 +51,6 @@ import { CreateTaskError } from './errors' import { stringToHash } from './helpers' import { logger } from './logger' import View = google.cloud.tasks.v2.Task.View -import { AISummarizeJobData, AI_SUMMARIZE_JOB_NAME } from '../jobs/ai-summarize' -import { - PROCESS_YOUTUBE_TRANSCRIPT_JOB_NAME, - PROCESS_YOUTUBE_VIDEO_JOB_NAME, - ProcessYouTubeTranscriptJobData, - ProcessYouTubeVideoJobData, -} from '../jobs/process-youtube-video' // Instantiates a client. const client = new CloudTasksClient() @@ -594,7 +594,7 @@ export const enqueueImportFromIntegration = async ( return createdTasks[0].name } -export const enqueueExportAllItems = async ( +export const enqueueExportToIntegration = async ( integrationId: string, userId: string ) => {