0

New or Updated Issue

by
Published today

Emit issues created or updated since the last poll, optionally for one team.

Scriptยท trigger linear Verified

The script

Submitted by hugo989 Typescript (fetch-only)
Verified 1 hour ago
1
//native
2

3
import * as wmill from "windmill-client"
4

5
/**
6
 * New or Updated Issue
7
 * Emits issues created or updated since the last poll (oldest first), tracked by an updatedAt watermark in Windmill state. The first run only sets the watermark. Optionally restrict to one team.
8
 */
9
export async function main(auth: RT.Linear, team_id: string | undefined) {
10
  const lastChecked: string | undefined = await wmill.getState()
11

12
  const filter: { [key: string]: any } = {}
13
  if (team_id) filter.team = { id: { eq: team_id } }
14
  if (lastChecked) filter.updatedAt = { gt: lastChecked }
15

16
  const issues: { updatedAt: string; [key: string]: any }[] = []
17
  let after: string | undefined
18
  do {
19
    const response = await fetch("https://api.linear.app/graphql", {
20
      method: "POST",
21
      headers: {
22
        Authorization: auth.apiKey,
23
        "Content-Type": "application/json",
24
        Accept: "application/json",
25
      },
26
      body: JSON.stringify({
27
        query: `query ($filter: IssueFilter, $first: Int, $after: String) { issues(filter: $filter, orderBy: updatedAt, first: $first, after: $after) { nodes { id identifier title description url priority priorityLabel dueDate createdAt updatedAt state { id name type } assignee { id name email } team { id key name } project { id name } labels { nodes { id name } } } pageInfo { hasNextPage endCursor } } }`,
28
        // First run: only the most recently updated issue is needed to seed the watermark.
29
        variables: { filter, first: lastChecked ? 100 : 1, after },
30
      }),
31
    })
32

33
    if (!response.ok) {
34
      throw new Error(`${response.status} ${await response.text()}`)
35
    }
36

37
    const { data, errors } = await response.json()
38
    if (errors) {
39
      throw new Error(JSON.stringify(errors))
40
    }
41

42
    issues.push(...data.issues.nodes)
43
    after =
44
      lastChecked && data.issues.pageInfo.hasNextPage
45
        ? data.issues.pageInfo.endCursor
46
        : undefined
47
  } while (after)
48

49
  // ISO 8601 UTC timestamps sort lexicographically.
50
  issues.sort((a, b) => a.updatedAt.localeCompare(b.updatedAt))
51
  const newest = issues.at(-1)?.updatedAt
52
  if (newest) await wmill.setState(newest)
53

54
  return lastChecked ? issues : []
55
}
56