@rawdash/connector-clickup 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../connector-shared/src/errors.ts","../../../connector-shared/src/retry.ts","../../../connector-shared/src/version.ts","../../../connector-shared/src/request.ts","../../../connector-shared/src/rate-limit.ts","../../../connector-shared/src/map-concurrent.ts","../../../connector-shared/src/sanitize.ts","../../../connector-shared/src/epoch.ts","../../../connector-shared/src/pagination.ts","../../../connector-shared/src/logger.ts","../src/clickup.ts","../src/index.ts"],"sourcesContent":["import type { HttpResponse } from './types';\n\nexport type HttpErrorKind =\n | 'transient'\n | 'rate_limit'\n | 'auth'\n | 'upstream_bug'\n | 'client_bug';\n\nexport abstract class HttpClientError extends Error {\n abstract readonly kind: HttpErrorKind;\n readonly response?: HttpResponse;\n\n constructor(message: string, response?: HttpResponse) {\n super(message);\n this.name = new.target.name;\n this.response = response;\n }\n}\n\nexport class TransientError extends HttpClientError {\n readonly kind = 'transient' as const;\n}\n\nexport class RateLimitError extends HttpClientError {\n readonly kind = 'rate_limit' as const;\n readonly retryAfter?: Date;\n\n constructor(message: string, response?: HttpResponse, retryAfter?: Date) {\n super(message, response);\n this.retryAfter = retryAfter;\n }\n}\n\nexport class AuthError extends HttpClientError {\n readonly kind = 'auth' as const;\n}\n\nexport class UpstreamBugError extends HttpClientError {\n readonly kind = 'upstream_bug' as const;\n}\n\nexport class ClientBugError extends HttpClientError {\n readonly kind = 'client_bug' as const;\n}\n\nexport function classifyStatus(status: number): HttpErrorKind {\n if (status === 429) {\n return 'rate_limit';\n }\n if (status === 401 || status === 403) {\n return 'auth';\n }\n if (status === 408) {\n return 'transient';\n }\n if (status >= 500) {\n return 'upstream_bug';\n }\n if (status >= 400) {\n return 'client_bug';\n }\n return 'client_bug';\n}\n\nexport function errorForStatus(\n message: string,\n response: HttpResponse,\n retryAfter?: Date,\n): HttpClientError {\n const kind = classifyStatus(response.status);\n switch (kind) {\n case 'rate_limit':\n return new RateLimitError(message, response, retryAfter);\n case 'auth':\n return new AuthError(message, response);\n case 'transient':\n return new TransientError(message, response);\n case 'upstream_bug':\n return new UpstreamBugError(message, response);\n case 'client_bug':\n return new ClientBugError(message, response);\n }\n}\n","import { HttpClientError, RateLimitError, TransientError } from './errors';\n\nexport interface RetryPolicy {\n maxAttempts?: number;\n initialDelayMs?: number;\n maxDelayMs?: number;\n retryOn?: (status: number | null, err?: Error) => boolean;\n}\n\nexport const defaultRetryOn = (status: number | null, err?: Error): boolean => {\n if (err instanceof RateLimitError) {\n return true;\n }\n if (err instanceof TransientError) {\n return true;\n }\n if (status === null) {\n return err instanceof Error && !(err instanceof HttpClientError);\n }\n if (status === 408 || status === 429) {\n return true;\n }\n if (status >= 500) {\n return true;\n }\n return false;\n};\n\nexport function backoffDelayMs(\n attempt: number,\n policy: Required<Pick<RetryPolicy, 'initialDelayMs' | 'maxDelayMs'>>,\n): number {\n const base = policy.initialDelayMs * 2 ** attempt;\n const jitter = base * 0.25 * Math.random();\n return Math.min(base + jitter, policy.maxDelayMs);\n}\n\nexport function parseRetryAfter(\n headerValue: string | null,\n now: Date = new Date(),\n): Date | undefined {\n if (!headerValue) {\n return undefined;\n }\n const trimmed = headerValue.trim();\n if (/^\\d+$/.test(trimmed)) {\n return new Date(now.getTime() + Number(trimmed) * 1000);\n }\n const parsed = Date.parse(trimmed);\n if (Number.isNaN(parsed)) {\n return undefined;\n }\n return new Date(parsed);\n}\n\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) {\n return Promise.reject(signal.reason ?? new Error('Aborted'));\n }\n return new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal!.reason ?? new Error('Aborted'));\n };\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n","export const HTTP_CLIENT_VERSION = '0.0.0';\n\nexport const DEFAULT_USER_AGENT = `rawdash-connector/${HTTP_CLIENT_VERSION} (+https://rawdash.dev)`;\n\nexport function connectorUserAgent(connectorId: string): string {\n return `rawdash-connector-${connectorId}/${HTTP_CLIENT_VERSION} (+https://rawdash.dev)`;\n}\n","import {\n AuthError,\n ClientBugError,\n HttpClientError,\n RateLimitError,\n TransientError,\n UpstreamBugError,\n errorForStatus,\n} from './errors';\nimport { defaultRetryOn, parseRetryAfter, sleep } from './retry';\nimport type { FetchLike, HttpMethod, HttpRequest, HttpResponse } from './types';\nimport { DEFAULT_USER_AGENT } from './version';\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_MAX_ATTEMPTS = 3;\nconst DEFAULT_INITIAL_DELAY_MS = 1000;\nconst DEFAULT_MAX_DELAY_MS = 60_000;\nconst OBSERVER_TIMEOUT_MS = 250;\n\nexport interface RequestObservation {\n url: string;\n method: HttpMethod;\n status: number;\n resource: string;\n requestId: string;\n body: unknown;\n}\n\nexport type RequestObserver = (\n event: RequestObservation,\n) => void | Promise<void>;\n\nexport interface RequestOptions {\n fetch?: FetchLike;\n observer?: RequestObserver;\n resource: string;\n requestId?: string;\n}\n\nasync function notifyObserver(\n observer: RequestObserver,\n event: RequestObservation,\n): Promise<void> {\n let result: void | Promise<void>;\n try {\n result = observer(event);\n } catch (err) {\n console.warn('[connector-shared] request observer threw:', err);\n return;\n }\n if (!(result instanceof Promise)) {\n return;\n }\n const guarded = result.catch((err) => {\n console.warn('[connector-shared] request observer rejected:', err);\n });\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<void>((resolve) => {\n timer = setTimeout(resolve, OBSERVER_TIMEOUT_MS);\n });\n try {\n await Promise.race([guarded, timeout]);\n } finally {\n if (timer) {\n clearTimeout(timer);\n }\n }\n}\n\nfunction newRequestId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n if (c?.randomUUID) {\n return c.randomUUID();\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction mergeHeaders(\n defaults: Record<string, string>,\n overrides: Record<string, string> | undefined,\n): Record<string, string> {\n const merged: Record<string, string> = {};\n for (const [k, v] of Object.entries(defaults)) {\n merged[k.toLowerCase()] = v;\n }\n if (overrides) {\n for (const [k, v] of Object.entries(overrides)) {\n merged[k.toLowerCase()] = v;\n }\n }\n return merged;\n}\n\nfunction linkTimeoutSignal(\n parent: AbortSignal | undefined,\n timeoutMs: number,\n): { signal: AbortSignal; cancel: () => void } {\n const controller = new AbortController();\n const onParentAbort = () => {\n controller.abort(parent?.reason);\n };\n if (parent) {\n if (parent.aborted) {\n controller.abort(parent.reason);\n } else {\n parent.addEventListener('abort', onParentAbort, { once: true });\n }\n }\n const timer = setTimeout(() => {\n controller.abort(new Error(`Request timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n return {\n signal: controller.signal,\n cancel: () => {\n clearTimeout(timer);\n if (parent) {\n parent.removeEventListener('abort', onParentAbort);\n }\n },\n };\n}\n\nasync function readBody(res: Response, parseJson: boolean): Promise<unknown> {\n if (res.status === 204 || res.status === 205) {\n return null;\n }\n const contentType = res.headers.get('content-type') ?? '';\n if (parseJson && contentType.includes('application/json')) {\n const text = await res.text();\n if (text.length === 0) {\n return null;\n }\n return JSON.parse(text);\n }\n return res.text();\n}\n\nexport async function request<T = unknown>(\n req: HttpRequest,\n options: RequestOptions,\n): Promise<HttpResponse<T>> {\n const fetchImpl: FetchLike = options.fetch ?? (globalThis.fetch as FetchLike);\n const retry = req.retry ?? {};\n const maxAttempts = retry.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;\n const initialDelayMs = retry.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS;\n const maxDelayMs = retry.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;\n const retryOn = retry.retryOn ?? defaultRetryOn;\n const timeoutMs = req.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const parseJson = req.parseJson ?? true;\n\n const headers = mergeHeaders(\n {\n 'User-Agent': DEFAULT_USER_AGENT,\n Accept: 'application/json',\n },\n req.headers,\n );\n\n let lastErr: Error | undefined;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n req.signal?.throwIfAborted();\n\n const { signal, cancel } = linkTimeoutSignal(req.signal, timeoutMs);\n let res: Response;\n try {\n res = await fetchImpl(req.url, {\n method: req.method ?? 'GET',\n headers,\n body: req.body as RequestInit['body'],\n signal,\n });\n } catch (err) {\n cancel();\n if (req.signal?.aborted) {\n throw req.signal.reason ?? err;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n lastErr = error;\n if (attempt < maxAttempts - 1 && retryOn(null, error)) {\n const delay = computeDelay(attempt, initialDelayMs, maxDelayMs);\n await sleep(delay, req.signal);\n continue;\n }\n throw new TransientError(error.message);\n }\n cancel();\n\n const body = await readBody(res, parseJson);\n const httpResponse: HttpResponse<T> = {\n status: res.status,\n headers: res.headers,\n body: body as T,\n };\n if (req.rateLimit) {\n const state = req.rateLimit.parse(res.headers);\n if (state) {\n httpResponse.rateLimitState = state;\n }\n }\n\n if (options.observer) {\n await notifyObserver(options.observer, {\n url: req.url,\n method: req.method ?? 'GET',\n status: res.status,\n resource: options.resource,\n requestId: options.requestId ?? newRequestId(),\n body,\n });\n }\n\n if (res.ok) {\n return httpResponse;\n }\n\n const retryAfter = parseRetryAfter(res.headers.get('retry-after'));\n const message = `HTTP ${res.status} ${res.statusText} for ${req.method ?? 'GET'} ${req.url}`;\n const err = errorForStatus(message, httpResponse, retryAfter);\n\n if (\n attempt < maxAttempts - 1 &&\n retryOn(res.status, err) &&\n !(err instanceof AuthError) &&\n !(err instanceof ClientBugError)\n ) {\n lastErr = err;\n let delay = computeDelay(attempt, initialDelayMs, maxDelayMs);\n if (err instanceof RateLimitError && retryAfter) {\n const wait = retryAfter.getTime() - Date.now();\n if (wait > 0) {\n delay = Math.min(wait, maxDelayMs);\n }\n }\n await sleep(delay, req.signal);\n continue;\n }\n\n throw err;\n }\n\n throw lastErr ?? new UpstreamBugError('Exhausted retry attempts');\n}\n\nfunction computeDelay(\n attempt: number,\n initialDelayMs: number,\n maxDelayMs: number,\n): number {\n const base = initialDelayMs * 2 ** attempt;\n const jitter = base * 0.25 * Math.random();\n return Math.min(base + jitter, maxDelayMs);\n}\n\nexport { HttpClientError };\n","export interface RateLimitState {\n remaining: number;\n resetAt: Date;\n}\n\nexport interface RateLimitPolicy {\n parse(headers: Headers): RateLimitState | null;\n}\n\nexport interface StandardRateLimitPolicyConfig {\n remainingHeader: string;\n resetHeader: string;\n resetUnit: 's' | 'ms';\n resetFallbackMs?: number;\n}\n\nexport function standardRateLimitPolicy(\n config: StandardRateLimitPolicyConfig,\n): RateLimitPolicy {\n const { remainingHeader, resetHeader, resetUnit, resetFallbackMs } = config;\n const multiplier = resetUnit === 's' ? 1000 : 1;\n return {\n parse(h) {\n const remainingRaw = h.get(remainingHeader);\n if (remainingRaw === null || remainingRaw.trim() === '') {\n return null;\n }\n const remaining = Number(remainingRaw);\n if (!Number.isFinite(remaining)) {\n return null;\n }\n const resetRaw = h.get(resetHeader);\n if (resetRaw === null) {\n if (resetFallbackMs === undefined) {\n return null;\n }\n return {\n remaining,\n resetAt: new Date(Date.now() + resetFallbackMs),\n };\n }\n if (resetRaw.trim() === '') {\n return null;\n }\n const reset = Number(resetRaw);\n if (!Number.isFinite(reset) || reset < 0) {\n return null;\n }\n const resetMs = reset * multiplier;\n if (!Number.isFinite(resetMs)) {\n return null;\n }\n return { remaining, resetAt: new Date(resetMs) };\n },\n };\n}\n","export async function mapWithConcurrency<T, R>(\n items: readonly T[],\n concurrency: number,\n fn: (item: T, index: number) => Promise<R>,\n): Promise<R[]> {\n const results = new Array<R>(items.length);\n if (items.length === 0) {\n return results;\n }\n const normalized = Number.isFinite(concurrency) ? Math.floor(concurrency) : 1;\n const limit = Math.max(1, Math.min(normalized, items.length));\n let next = 0;\n let failed = false;\n\n async function worker(): Promise<void> {\n while (!failed) {\n const i = next++;\n if (i >= items.length) {\n return;\n }\n try {\n results[i] = await fn(items[i]!, i);\n } catch (err) {\n failed = true;\n throw err;\n }\n }\n }\n\n const workers: Promise<void>[] = [];\n for (let w = 0; w < limit; w++) {\n workers.push(worker());\n }\n await Promise.all(workers);\n return results;\n}\n","export interface SanitizeAllowedUrlOptions {\n url: string | null;\n host: string;\n pathname: string;\n protocol?: 'https:' | 'http:';\n}\n\nexport function sanitizeAllowedUrl(\n options: SanitizeAllowedUrlOptions,\n): string | null {\n const { url, host, pathname, protocol = 'https:' } = options;\n if (url === null) {\n return null;\n }\n try {\n const u = new URL(url);\n if (u.protocol !== protocol || u.host !== host || u.pathname !== pathname) {\n return null;\n }\n return u.toString();\n } catch {\n return null;\n }\n}\n","export type EpochUnit = 'ms' | 's' | 'iso';\n\nexport function parseEpoch(\n value: number | string | null | undefined,\n unit: EpochUnit,\n): number | null {\n if (value === null || value === undefined) {\n return null;\n }\n if (unit === 'iso') {\n if (typeof value !== 'string') {\n return null;\n }\n const ms = new Date(value).getTime();\n return Number.isFinite(ms) ? ms : null;\n }\n if (typeof value === 'string' && value.trim() === '') {\n return null;\n }\n const n = typeof value === 'number' ? value : Number(value);\n if (!Number.isFinite(n)) {\n return null;\n }\n const result = unit === 's' ? n * 1000 : n;\n return Number.isFinite(result) ? result : null;\n}\n","import { request } from './request';\nimport type { HttpRequest } from './types';\n\nexport function parseLinkHeader(header: string | null): Record<string, string> {\n if (!header) {\n return {};\n }\n const result: Record<string, string> = {};\n for (const part of header.split(',')) {\n const match = part.match(/<([^>]+)>\\s*;\\s*rel=\"([^\"]+)\"/);\n if (match) {\n result[match[2]!] = match[1]!;\n }\n }\n return result;\n}\n\nexport async function* paginateLink<T>(\n initial: HttpRequest,\n parse: (body: unknown) => T[],\n options: { resource: string },\n): AsyncIterable<T> {\n let next: string | null = initial.url;\n while (next) {\n const res: Awaited<ReturnType<typeof request>> = await request(\n {\n ...initial,\n url: next,\n },\n { resource: options.resource },\n );\n for (const item of parse(res.body)) {\n yield item;\n }\n const links = parseLinkHeader(res.headers.get('link'));\n next = links['next'] ?? null;\n }\n}\n\nexport async function* paginateCursor<T>(\n initial: HttpRequest,\n parse: (body: unknown) => { items: T[]; nextCursor: string | null },\n buildNext: (req: HttpRequest, cursor: string) => HttpRequest,\n options: { resource: string },\n): AsyncIterable<T> {\n let req: HttpRequest = initial;\n while (true) {\n const res = await request(req, { resource: options.resource });\n const { items, nextCursor } = parse(res.body);\n for (const item of items) {\n yield item;\n }\n if (!nextCursor) {\n return;\n }\n req = buildNext(req, nextCursor);\n }\n}\n\nexport async function* paginatePage<T>(\n initial: HttpRequest,\n parse: (body: unknown) => { items: T[]; hasMore: boolean },\n buildPage: (req: HttpRequest, page: number) => HttpRequest,\n options: { resource: string },\n): AsyncIterable<T> {\n let page = 1;\n while (true) {\n const req = page === 1 ? initial : buildPage(initial, page);\n const res = await request(req, { resource: options.resource });\n const { items, hasMore } = parse(res.body);\n for (const item of items) {\n yield item;\n }\n if (!hasMore || items.length === 0) {\n return;\n }\n page++;\n }\n}\n","export type LogFields = Record<string, unknown>;\n\nexport interface ConnectorLogger {\n info(event: string, fields?: LogFields): void;\n warn(event: string, fields?: LogFields): void;\n}\n\nexport interface ConnectorLoggerOptions {\n scope: string;\n}\n\nconst MAX_VALUE_LEN = 120;\n\nfunction truncate(s: string, max = MAX_VALUE_LEN): string {\n if (s.length <= max) {\n return s;\n }\n return `${s.slice(0, max - 1)}…`;\n}\n\nfunction formatValue(value: unknown): string {\n if (value === null) {\n return 'null';\n }\n if (value === undefined) {\n return '';\n }\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n if (typeof value === 'string') {\n const t = truncate(value);\n if (/[\\s\"=]/.test(t)) {\n return JSON.stringify(t);\n }\n return t;\n }\n if (typeof value === 'bigint') {\n return value.toString();\n }\n let json: string | undefined;\n try {\n json = JSON.stringify(value);\n } catch {\n json = undefined;\n }\n return truncate(json ?? String(value));\n}\n\nexport function formatLogFields(fields?: LogFields): string {\n if (!fields) {\n return '';\n }\n const parts: string[] = [];\n for (const [k, v] of Object.entries(fields)) {\n if (v === undefined) {\n continue;\n }\n parts.push(`${k}=${formatValue(v)}`);\n }\n return parts.length > 0 ? ` ${parts.join(' ')}` : '';\n}\n\nexport function formatLogLine(\n scope: string,\n event: string,\n fields?: LogFields,\n): string {\n return `[${scope}] ${event}${formatLogFields(fields)}`;\n}\n\nexport function createDefaultConnectorLogger(\n opts: ConnectorLoggerOptions,\n): ConnectorLogger {\n return {\n info(event, fields) {\n console.info(formatLogLine(opts.scope, event, fields));\n },\n warn(event, fields) {\n console.warn(formatLogLine(opts.scope, event, fields));\n },\n };\n}\n\nconst NOOP_LOGGER: ConnectorLogger = {\n info() {},\n warn() {},\n};\n\nexport function noopConnectorLogger(): ConnectorLogger {\n return NOOP_LOGGER;\n}\n","import {\n type HttpResponse,\n connectorUserAgent,\n parseEpoch,\n standardRateLimitPolicy,\n} from '@rawdash/connector-shared';\nimport {\n BaseConnector,\n type ConnectorContext,\n type ConnectorDoc,\n type CredentialsSchema,\n type FetchPageResult,\n type FetchSpec,\n type FilterClause,\n type JSONValue,\n type StorageHandle,\n type SyncOptions,\n type SyncResult,\n defineConfigFields,\n defineConnectorDoc,\n defineResources,\n makeChunkedCursorGuard,\n paginateChunked,\n schemasFromResources,\n selectActivePhases,\n} from '@rawdash/core';\nimport { z } from 'zod';\n\nexport const configFields = defineConfigFields(\n z.object({\n apiToken: z.object({ $secret: z.string() }).meta({\n label: 'API Token',\n description:\n 'ClickUp personal API token. Create one at ClickUp -> Settings -> Apps -> API Token.',\n placeholder: 'pk_...',\n secret: true,\n }),\n teamId: z.string().min(1).meta({\n label: 'Workspace ID',\n description:\n 'ClickUp Workspace (team) ID to sync. Find it in the URL: app.clickup.com/<workspace_id>/home.',\n placeholder: '9000000000',\n }),\n resources: z\n .array(z.enum(['spaces', 'folders', 'lists', 'tasks', 'task_events']))\n .nonempty()\n .optional()\n .meta({\n label: 'Resources',\n description:\n \"Which ClickUp resources to sync. Omit to sync all of them. 'task_events' derives created / closed lifecycle events from each task's timestamps and shares the task query with 'tasks'.\",\n }),\n }),\n);\n\nexport const doc: ConnectorDoc = defineConnectorDoc({\n displayName: 'ClickUp',\n category: 'product',\n brandColor: '#7B68EE',\n tagline:\n 'Sync spaces, folders, lists, tasks, and task lifecycle events from a ClickUp workspace for throughput, open-work, and status-distribution analytics.',\n vendor: {\n name: 'ClickUp',\n domain: 'clickup.com',\n apiDocs: 'https://clickup.com/api',\n website: 'https://clickup.com',\n },\n auth: {\n summary:\n 'Authenticates with a ClickUp personal API token sent in the Authorization header. The token scopes the sync to the workspaces, spaces, and tasks the issuing user can access.',\n setup: [\n 'Open ClickUp -> Settings -> Apps.',\n 'Under API Token, click Generate (or copy the existing personal token). It starts with pk_.',\n 'Store it as a secret and reference it from the connector config as `apiToken: secret(\"CLICKUP_API_TOKEN\")`, alongside your Workspace ID.',\n ],\n },\n rateLimit:\n 'ClickUp rate-limits per token (100 requests/minute on the Free Forever / Unlimited plans, higher on Business+) and exposes X-RateLimit-Remaining / X-RateLimit-Reset headers; the shared HTTP client backs off on 429.',\n limitations: [\n 'Personal API token auth only (OAuth app installs are out of scope).',\n \"Task lifecycle events (created / closed) are derived from each task's own date_created / date_closed fields rather than the per-task activity feed, which avoids an N+1 sync; the event scope is cleared and rewritten from a full task scan on every sync.\",\n 'Custom fields, comments, time tracking, and goals are out of scope.',\n ],\n});\n\nexport interface ClickUpSettings {\n teamId: string;\n resources?: readonly ClickUpResource[];\n}\n\nconst clickupCredentials = {\n apiToken: {\n description: 'ClickUp personal API token',\n auth: 'required' as const,\n },\n} satisfies CredentialsSchema;\n\ntype ClickUpCredentials = typeof clickupCredentials;\n\nconst clickupRateLimit = standardRateLimitPolicy({\n remainingHeader: 'x-ratelimit-remaining',\n resetHeader: 'x-ratelimit-reset',\n resetUnit: 's',\n resetFallbackMs: 60_000,\n});\n\nconst PHASE_ORDER = [\n 'spaces',\n 'folders',\n 'lists',\n 'tasks',\n 'task_events',\n] as const;\n\ntype ClickUpPhase = (typeof PHASE_ORDER)[number];\n\nexport type ClickUpResource = ClickUpPhase;\n\nconst isClickUpSyncCursor = makeChunkedCursorGuard(PHASE_ORDER);\n\nconst SPACE_ENTITY = 'clickup_space';\nconst FOLDER_ENTITY = 'clickup_folder';\nconst LIST_ENTITY = 'clickup_list';\nconst TASK_ENTITY = 'clickup_task';\nconst TASK_EVENT = 'clickup_task_event';\n\nconst API_BASE = 'https://api.clickup.com/api/v2';\nconst TASKS_PER_PAGE = 100;\n\nconst idString = z.string().min(1);\n\nconst spaceSchema = z.object({\n id: idString,\n name: z.string(),\n private: z.boolean().nullish(),\n archived: z.boolean().nullish(),\n});\n\nconst spacesResponseSchema = z.object({\n spaces: z.array(spaceSchema).nullish(),\n});\n\nconst folderSchema = z.object({\n id: idString,\n name: z.string(),\n hidden: z.boolean().nullish(),\n archived: z.boolean().nullish(),\n task_count: z.union([z.string(), z.number()]).nullish(),\n space: z.object({ id: idString, name: z.string().nullish() }).nullish(),\n});\n\nconst foldersResponseSchema = z.object({\n folders: z.array(folderSchema).nullish(),\n});\n\nconst listSchema = z.object({\n id: idString,\n name: z.string(),\n archived: z.boolean().nullish(),\n task_count: z.number().nullish(),\n status: z.object({ status: z.string().nullish() }).nullish(),\n folder: z.object({ id: idString, name: z.string().nullish() }).nullish(),\n space: z.object({ id: idString, name: z.string().nullish() }).nullish(),\n});\n\nconst listsResponseSchema = z.object({\n lists: z.array(listSchema).nullish(),\n});\n\nconst taskSchema = z.object({\n id: idString,\n name: z.string(),\n status: z\n .object({ status: z.string().nullish(), type: z.string().nullish() })\n .nullish(),\n priority: z.object({ priority: z.string().nullish() }).nullish(),\n date_created: z.string().nullish(),\n date_updated: z.string().nullish(),\n date_closed: z.string().nullish(),\n date_done: z.string().nullish(),\n due_date: z.string().nullish(),\n time_estimate: z.number().nullish(),\n creator: z.object({ id: z.union([z.string(), z.number()]) }).nullish(),\n assignees: z\n .array(z.object({ id: z.union([z.string(), z.number()]) }))\n .nullish(),\n tags: z.array(z.object({ name: z.string() })).nullish(),\n url: z.string().nullish(),\n list: z.object({ id: idString, name: z.string().nullish() }).nullish(),\n folder: z.object({ id: idString, name: z.string().nullish() }).nullish(),\n space: z.object({ id: idString }).nullish(),\n});\n\nconst tasksResponseSchema = z.object({\n tasks: z.array(taskSchema).nullish(),\n last_page: z.boolean().nullish(),\n});\n\ntype SpaceRecord = z.infer<typeof spaceSchema>;\ntype FolderRecord = z.infer<typeof folderSchema>;\ntype ListRecord = z.infer<typeof listSchema>;\ntype TaskRecord = z.infer<typeof taskSchema>;\n\ninterface SpacesResponse {\n spaces?: SpaceRecord[] | null;\n}\ninterface FoldersResponse {\n folders?: FolderRecord[] | null;\n}\ninterface ListsResponse {\n lists?: ListRecord[] | null;\n}\ninterface TasksResponse {\n tasks?: TaskRecord[] | null;\n last_page?: boolean | null;\n}\n\nexport const clickupResources = defineResources({\n [SPACE_ENTITY]: {\n shape: 'entity',\n filterable: [],\n description: 'Workspace spaces with their name and privacy flag.',\n endpoint: 'GET /team/{team_id}/space',\n fields: [\n { name: 'name', description: 'Space name.' },\n { name: 'private', description: 'Whether the space is private.' },\n { name: 'archived', description: 'Whether the space is archived.' },\n ],\n responses: { spaces: spacesResponseSchema },\n },\n [FOLDER_ENTITY]: {\n shape: 'entity',\n filterable: [{ field: 'spaceId', ops: ['eq'] }],\n description: 'Folders within each space, with their parent space.',\n endpoint: 'GET /space/{space_id}/folder',\n fields: [\n { name: 'name', description: 'Folder name.' },\n { name: 'spaceId', description: 'Parent space id.' },\n {\n name: 'taskCount',\n description: 'Number of tasks across the folder at sync time.',\n },\n { name: 'archived', description: 'Whether the folder is archived.' },\n ],\n responses: { folders: foldersResponseSchema },\n },\n [LIST_ENTITY]: {\n shape: 'entity',\n filterable: [{ field: 'spaceId', ops: ['eq'] }],\n description:\n 'Lists (folder-scoped and folderless) with their parent folder and space.',\n endpoint: 'GET /space/{space_id}/list and GET /folder/{folder_id}/list',\n fields: [\n { name: 'name', description: 'List name.' },\n {\n name: 'folderId',\n description: 'Parent folder id (null if folderless).',\n },\n { name: 'spaceId', description: 'Parent space id.' },\n {\n name: 'taskCount',\n description: 'Number of tasks in the list at sync time.',\n },\n { name: 'archived', description: 'Whether the list is archived.' },\n ],\n responses: { lists: listsResponseSchema },\n },\n [TASK_ENTITY]: {\n shape: 'entity',\n filterable: [\n {\n field: 'statusType',\n ops: ['eq'],\n values: ['open', 'custom', 'closed', 'done'],\n },\n { field: 'status', ops: ['eq'] },\n { field: 'listId', ops: ['eq'] },\n ],\n description:\n 'Tasks with their status, priority, assignees, parent list / folder / space, tags, and lifecycle timestamps.',\n endpoint: 'GET /team/{team_id}/task',\n fields: [\n { name: 'name', description: 'Task name.' },\n {\n name: 'status',\n description: 'Current status name (e.g. \"in progress\").',\n },\n {\n name: 'statusType',\n description: 'Status category: open, custom, closed, or done.',\n },\n {\n name: 'priority',\n description: 'Priority label (urgent / high / normal / low), or null.',\n },\n { name: 'listId', description: 'Parent list id.' },\n { name: 'folderId', description: 'Parent folder id.' },\n { name: 'spaceId', description: 'Parent space id.' },\n { name: 'assignees', description: 'Assignee user ids.' },\n { name: 'assigneeCount', description: 'Number of assignees.' },\n { name: 'tags', description: 'Tag names on the task.' },\n {\n name: 'createdAt',\n description: 'When the task was created (Unix ms).',\n },\n {\n name: 'closedAt',\n description: 'When the task was closed (Unix ms; null if open).',\n },\n {\n name: 'dueDate',\n description: 'Task due date (Unix ms; null if unset).',\n },\n ],\n responses: { tasks: tasksResponseSchema },\n },\n [TASK_EVENT]: {\n shape: 'event',\n filterable: [\n { field: 'kind', ops: ['eq'], values: ['created', 'closed'] },\n { field: 'listId', ops: ['eq'] },\n ],\n description:\n \"Task lifecycle events (created / closed) derived from each task's date_created and date_closed. The scope is cleared and rewritten from a full task scan on every sync (including incremental runs).\",\n endpoint: 'GET /team/{team_id}/task',\n notes:\n \"Derived from each task's own date_created / date_closed timestamps, not from a separate per-task activity call. Drives created-per-day and closed-per-day throughput timeseries.\",\n fields: [\n { name: 'kind', description: '\"created\" or \"closed\".' },\n { name: 'taskId', description: 'Task the event belongs to.' },\n { name: 'listId', description: 'Parent list id, denormalised.' },\n { name: 'spaceId', description: 'Parent space id, denormalised.' },\n { name: 'status', description: 'Task status name at sync time.' },\n ],\n responses: { task_events: tasksResponseSchema },\n },\n});\n\nexport const id = 'clickup';\n\nfunction epochMs(value: string | null | undefined): number | null {\n return parseEpoch(value ?? null, 'ms');\n}\n\nfunction tagNames(tags: Array<{ name: string }> | null | undefined): string[] {\n if (!tags) {\n return [];\n }\n return tags\n .map((t) => t.name)\n .filter((n) => typeof n === 'string' && n !== '');\n}\n\nfunction assigneeIds(\n assignees: Array<{ id: string | number }> | null | undefined,\n): string[] {\n if (!assignees) {\n return [];\n }\n return assignees.map((a) => String(a.id));\n}\n\nfunction pushableEq(\n filter: FilterClause[] | undefined,\n field: string,\n): string | null {\n if (!filter) {\n return null;\n }\n for (const clause of filter) {\n if (\n 'field' in clause &&\n clause.field === field &&\n clause.op === 'eq' &&\n typeof clause.value === 'string'\n ) {\n return clause.value;\n }\n }\n return null;\n}\n\nexport class ClickUpConnector extends BaseConnector<\n ClickUpSettings,\n ClickUpCredentials\n> {\n static readonly id = id;\n\n static readonly resources = clickupResources;\n\n static readonly schemas = schemasFromResources(clickupResources);\n\n static create(input: unknown, ctx?: ConnectorContext): ClickUpConnector {\n const parsed = configFields.parse(input);\n return new ClickUpConnector(\n { teamId: parsed.teamId, resources: parsed.resources },\n { apiToken: parsed.apiToken },\n ctx,\n );\n }\n\n readonly id = id;\n override readonly credentials = clickupCredentials;\n\n private spacesCache: SpaceRecord[] | undefined;\n\n private buildHeaders(): Record<string, string> {\n return {\n Authorization: this.creds.apiToken,\n Accept: 'application/json',\n 'User-Agent': connectorUserAgent('clickup'),\n };\n }\n\n private apiGet<T>(\n url: string,\n resource: string,\n signal?: AbortSignal,\n ): Promise<HttpResponse<T>> {\n return this.get<T>(url, {\n resource,\n headers: this.buildHeaders(),\n signal,\n rateLimit: clickupRateLimit,\n });\n }\n\n private get teamPath(): string {\n return `/team/${encodeURIComponent(this.settings.teamId)}`;\n }\n\n private async getSpaces(signal?: AbortSignal): Promise<SpaceRecord[]> {\n if (this.spacesCache) {\n return this.spacesCache;\n }\n const res = await this.apiGet<SpacesResponse>(\n `${API_BASE}${this.teamPath}/space?archived=false`,\n 'spaces',\n signal,\n );\n this.spacesCache = res.body.spaces ?? [];\n return this.spacesCache;\n }\n\n private async getFolders(\n spaceId: string,\n signal?: AbortSignal,\n ): Promise<FolderRecord[]> {\n const res = await this.apiGet<FoldersResponse>(\n `${API_BASE}/space/${encodeURIComponent(spaceId)}/folder?archived=false`,\n 'folders',\n signal,\n );\n return res.body.folders ?? [];\n }\n\n private async getFolderlessLists(\n spaceId: string,\n signal?: AbortSignal,\n ): Promise<ListRecord[]> {\n const res = await this.apiGet<ListsResponse>(\n `${API_BASE}/space/${encodeURIComponent(spaceId)}/list?archived=false`,\n 'lists',\n signal,\n );\n return res.body.lists ?? [];\n }\n\n private async getFolderLists(\n folderId: string,\n signal?: AbortSignal,\n ): Promise<ListRecord[]> {\n const res = await this.apiGet<ListsResponse>(\n `${API_BASE}/folder/${encodeURIComponent(folderId)}/list?archived=false`,\n 'lists',\n signal,\n );\n return res.body.lists ?? [];\n }\n\n private buildTasksUrl(\n page: number,\n options: SyncOptions,\n applySince: boolean,\n ): string {\n const url = new URL(`${API_BASE}${this.teamPath}/task`);\n url.searchParams.set('page', String(page));\n url.searchParams.set('include_closed', 'true');\n url.searchParams.set('subtasks', 'true');\n url.searchParams.set('order_by', 'updated');\n const listId = pushableEq(\n this.singleSpec(options, TASK_ENTITY)?.filter,\n 'listId',\n );\n if (listId !== null) {\n url.searchParams.append('list_ids[]', listId);\n }\n if (applySince && options.since) {\n const sinceMs = parseEpoch(options.since, 'iso');\n if (sinceMs !== null) {\n url.searchParams.set('date_updated_gt', String(sinceMs));\n }\n }\n return url.toString();\n }\n\n private singleSpec(\n options: SyncOptions,\n resource: string,\n ): FetchSpec | undefined {\n const specs = options.fetchSpecs?.[resource];\n return specs && specs.length === 1 ? specs[0] : undefined;\n }\n\n private async fetchSpacesPage(\n signal?: AbortSignal,\n ): Promise<FetchPageResult<string>> {\n const spaces = await this.getSpaces(signal);\n return { items: spaces, next: null };\n }\n\n private async fetchFoldersPage(\n signal?: AbortSignal,\n ): Promise<FetchPageResult<string>> {\n const spaces = await this.getSpaces(signal);\n const folders: FolderRecord[] = [];\n for (const space of spaces) {\n const spaceFolders = await this.getFolders(space.id, signal);\n for (const folder of spaceFolders) {\n folders.push({ ...folder, space: folder.space ?? { id: space.id } });\n }\n }\n return { items: folders, next: null };\n }\n\n private async fetchListsPage(\n signal?: AbortSignal,\n ): Promise<FetchPageResult<string>> {\n const spaces = await this.getSpaces(signal);\n const lists: ListRecord[] = [];\n for (const space of spaces) {\n const folderless = await this.getFolderlessLists(space.id, signal);\n for (const list of folderless) {\n lists.push({ ...list, space: list.space ?? { id: space.id } });\n }\n const folders = await this.getFolders(space.id, signal);\n for (const folder of folders) {\n const folderLists = await this.getFolderLists(folder.id, signal);\n for (const list of folderLists) {\n lists.push({\n ...list,\n folder: list.folder ?? { id: folder.id, name: folder.name },\n space: list.space ?? { id: space.id },\n });\n }\n }\n }\n return { items: lists, next: null };\n }\n\n private async fetchTasksPage(\n phase: 'tasks' | 'task_events',\n page: string | null,\n options: SyncOptions,\n signal?: AbortSignal,\n ): Promise<FetchPageResult<string>> {\n const pageNum = page === null ? 0 : Number(page);\n const safePage = Number.isFinite(pageNum) && pageNum >= 0 ? pageNum : 0;\n const url = this.buildTasksUrl(safePage, options, phase === 'tasks');\n const res = await this.apiGet<TasksResponse>(url, phase, signal);\n const tasks = res.body.tasks ?? [];\n const lastPage = res.body.last_page;\n const exhausted =\n tasks.length === 0 ||\n (typeof lastPage === 'boolean'\n ? lastPage\n : tasks.length < TASKS_PER_PAGE);\n return { items: tasks, next: exhausted ? null : String(safePage + 1) };\n }\n\n private async writeSpaces(\n storage: StorageHandle,\n spaces: SpaceRecord[],\n ): Promise<void> {\n for (const space of spaces) {\n await storage.entity({\n type: SPACE_ENTITY,\n id: space.id,\n attributes: {\n name: space.name,\n private: space.private ?? null,\n archived: space.archived ?? null,\n },\n updated_at: 0,\n });\n }\n }\n\n private async writeFolders(\n storage: StorageHandle,\n folders: FolderRecord[],\n ): Promise<void> {\n for (const folder of folders) {\n await storage.entity({\n type: FOLDER_ENTITY,\n id: folder.id,\n attributes: {\n name: folder.name,\n spaceId: folder.space?.id ?? null,\n taskCount:\n folder.task_count === null || folder.task_count === undefined\n ? null\n : Number(folder.task_count),\n archived: folder.archived ?? null,\n },\n updated_at: 0,\n });\n }\n }\n\n private async writeLists(\n storage: StorageHandle,\n lists: ListRecord[],\n ): Promise<void> {\n for (const list of lists) {\n await storage.entity({\n type: LIST_ENTITY,\n id: list.id,\n attributes: {\n name: list.name,\n folderId: list.folder?.id ?? null,\n spaceId: list.space?.id ?? null,\n taskCount: list.task_count ?? null,\n archived: list.archived ?? null,\n },\n updated_at: 0,\n });\n }\n }\n\n private async writeTasks(\n storage: StorageHandle,\n tasks: TaskRecord[],\n ): Promise<void> {\n for (const task of tasks) {\n const attributes: Record<string, JSONValue> = {\n name: task.name,\n status: task.status?.status ?? null,\n statusType: task.status?.type ?? null,\n priority: task.priority?.priority ?? null,\n listId: task.list?.id ?? null,\n folderId: task.folder?.id ?? null,\n spaceId: task.space?.id ?? null,\n assignees: assigneeIds(task.assignees),\n assigneeCount: task.assignees?.length ?? 0,\n tags: tagNames(task.tags),\n creatorId:\n task.creator?.id === null || task.creator?.id === undefined\n ? null\n : String(task.creator.id),\n url: task.url ?? null,\n timeEstimate: task.time_estimate ?? null,\n dueDate: epochMs(task.due_date),\n createdAt: epochMs(task.date_created),\n closedAt: epochMs(task.date_closed),\n doneAt: epochMs(task.date_done),\n };\n await storage.entity({\n type: TASK_ENTITY,\n id: task.id,\n attributes,\n updated_at:\n epochMs(task.date_updated) ?? epochMs(task.date_created) ?? 0,\n });\n }\n }\n\n private async writeTaskEvents(\n storage: StorageHandle,\n tasks: TaskRecord[],\n ): Promise<void> {\n for (const task of tasks) {\n const base: Record<string, JSONValue> = {\n taskId: task.id,\n listId: task.list?.id ?? null,\n spaceId: task.space?.id ?? null,\n status: task.status?.status ?? null,\n };\n\n const createdMs = epochMs(task.date_created);\n if (createdMs !== null) {\n await storage.event({\n name: TASK_EVENT,\n start_ts: createdMs,\n end_ts: null,\n attributes: { ...base, kind: 'created' },\n });\n }\n\n const closedMs = epochMs(task.date_closed);\n if (closedMs !== null) {\n await storage.event({\n name: TASK_EVENT,\n start_ts: closedMs,\n end_ts: null,\n attributes: { ...base, kind: 'closed' },\n });\n }\n }\n }\n\n private async clearScopeOnFirstPage(\n storage: StorageHandle,\n phase: ClickUpPhase,\n isFull: boolean,\n ): Promise<void> {\n if (phase === 'task_events') {\n await storage.events([], { names: [TASK_EVENT] });\n return;\n }\n if (!isFull) {\n return;\n }\n const entityType = ENTITY_TYPE_BY_PHASE[phase];\n if (entityType) {\n await storage.entities([], { types: [entityType] });\n }\n }\n\n private async writePhase(\n storage: StorageHandle,\n phase: ClickUpPhase,\n items: unknown[],\n ): Promise<void> {\n switch (phase) {\n case 'spaces':\n return this.writeSpaces(storage, items as SpaceRecord[]);\n case 'folders':\n return this.writeFolders(storage, items as FolderRecord[]);\n case 'lists':\n return this.writeLists(storage, items as ListRecord[]);\n case 'tasks':\n return this.writeTasks(storage, items as TaskRecord[]);\n case 'task_events':\n return this.writeTaskEvents(storage, items as TaskRecord[]);\n }\n }\n\n async sync(\n options: SyncOptions,\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<SyncResult> {\n this.spacesCache = undefined;\n const cursor = isClickUpSyncCursor(options.cursor)\n ? options.cursor\n : undefined;\n const isFull = options.mode === 'full';\n\n const phases = selectActivePhases<ClickUpResource, ClickUpPhase>(\n (r) => r,\n PHASE_ORDER,\n this.settings.resources,\n );\n\n return paginateChunked<ClickUpPhase, string>({\n phases,\n cursor,\n signal,\n logger: this.logger,\n fetchPage: async (phase, page, sig) => {\n switch (phase) {\n case 'spaces':\n return this.fetchSpacesPage(sig);\n case 'folders':\n return this.fetchFoldersPage(sig);\n case 'lists':\n return this.fetchListsPage(sig);\n case 'tasks':\n case 'task_events':\n return this.fetchTasksPage(phase, page, options, sig);\n }\n },\n writeBatch: async (phase, items, page) => {\n if (page === null) {\n await this.clearScopeOnFirstPage(storage, phase, isFull);\n }\n await this.writePhase(storage, phase, items);\n },\n });\n }\n}\n\nconst ENTITY_TYPE_BY_PHASE: Partial<Record<ClickUpPhase, string>> = {\n spaces: SPACE_ENTITY,\n folders: FOLDER_ENTITY,\n lists: LIST_ENTITY,\n tasks: TASK_ENTITY,\n};\n","import { ClickUpConnector } from './clickup';\n\nexport {\n ClickUpConnector,\n clickupResources as resources,\n configFields,\n doc,\n id,\n} from './clickup';\nexport type { ClickUpResource, ClickUpSettings } from './clickup';\nexport default ClickUpConnector;\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@rawdash/connector-clickup",
3
+ "version": "0.0.1",
4
+ "description": "Rawdash connector for ClickUp — spaces, folders, lists, tasks, and task lifecycle events",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/rawdash/rawdash.git",
11
+ "directory": "packages/connectors/clickup"
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "README.md",
16
+ "LICENSE"
17
+ ],
18
+ "exports": {
19
+ ".": {
20
+ "@rawdash/source": "./src/index.ts",
21
+ "types": "./dist/index.d.ts",
22
+ "import": "./dist/index.js"
23
+ }
24
+ },
25
+ "scripts": {
26
+ "build": "tsup",
27
+ "typecheck": "tsc --noEmit",
28
+ "lint": "eslint src",
29
+ "test": "vitest run"
30
+ },
31
+ "dependencies": {
32
+ "@rawdash/core": "workspace:*",
33
+ "zod": "^4.4.3"
34
+ },
35
+ "devDependencies": {
36
+ "@rawdash/connector-shared": "workspace:*",
37
+ "@rawdash/connector-test-utils": "workspace:*",
38
+ "fast-check": "^4.8.0",
39
+ "tsup": "^8.0.0",
40
+ "typescript": "^5.7.2",
41
+ "vitest": "^4.1.4"
42
+ }
43
+ }