The Linear Client SDK for interacting with the Linear GraphQL API
Comment and attachment operations for collaboration, communication, and file management within Linear issues and projects.
Create, update, and manage comments for issues and other entities.
/**
* Get comments with filtering and pagination
* @param variables - Query parameters including filters and pagination
* @returns Promise resolving to a connection of comments
*/
comments(variables?: CommentsQueryVariables): LinearFetch<CommentConnection>;
/**
* Get a single comment by ID
* @param id - The comment ID
* @returns Promise resolving to the comment
*/
comment(id: string): LinearFetch<Comment>;
/**
* Create a new comment
* @param input - Comment creation data
* @returns Promise resolving to the creation result
*/
createComment(input: CommentCreateInput): LinearFetch<CommentPayload>;
/**
* Update an existing comment
* @param id - The comment ID to update
* @param input - Comment update data
* @returns Promise resolving to the update result
*/
updateComment(id: string, input: CommentUpdateInput): LinearFetch<CommentPayload>;
/**
* Delete a comment
* @param id - The comment ID to delete
* @returns Promise resolving to the deletion result
*/
deleteComment(id: string): LinearFetch<DeletePayload>;
interface CommentCreateInput {
/** Comment body in markdown */
body: string;
/** Issue ID to comment on */
issueId?: string;
/** Project update ID to comment on */
projectUpdateId?: string;
/** Document ID to comment on */
documentId?: string;
/** Parent comment ID for replies */
parentId?: string;
}
interface CommentUpdateInput {
/** Update comment body */
body?: string;
}Usage Examples:
import { LinearClient } from "@linear/sdk";
const client = new LinearClient({ apiKey: "your-api-key" });
// Add comment to an issue
const newComment = await client.createComment({
issueId: "issue-id",
body: "This looks good to me! Ready to ship 🚀"
});
// Reply to a comment
const reply = await client.createComment({
issueId: "issue-id",
parentId: "parent-comment-id",
body: "I agree, let's merge this."
});
// Update comment content
const updatedComment = await client.updateComment("comment-id", {
body: "Updated comment with additional details"
});
// Get comments for an issue
const issueComments = await client.comments({
filter: {
issue: { id: { eq: "issue-id" } }
},
orderBy: PaginationOrderBy.CreatedAt
});Upload, manage, and associate file attachments with issues and other entities.
/**
* Get attachments with filtering and pagination
* @param variables - Query parameters including filters and pagination
* @returns Promise resolving to a connection of attachments
*/
attachments(variables?: AttachmentsQueryVariables): LinearFetch<AttachmentConnection>;
/**
* Get a single attachment by ID
* @param id - The attachment ID
* @returns Promise resolving to the attachment
*/
attachment(id: string): LinearFetch<Attachment>;
/**
* Create a new attachment
* @param input - Attachment creation data
* @returns Promise resolving to the creation result
*/
createAttachment(input: AttachmentCreateInput): LinearFetch<AttachmentPayload>;
/**
* Update an attachment
* @param id - The attachment ID to update
* @param input - Attachment update data
* @returns Promise resolving to the update result
*/
updateAttachment(id: string, input: AttachmentUpdateInput): LinearFetch<AttachmentPayload>;
/**
* Delete an attachment
* @param id - The attachment ID to delete
* @returns Promise resolving to the deletion result
*/
deleteAttachment(id: string): LinearFetch<DeletePayload>;
interface AttachmentCreateInput {
/** Attachment title */
title?: string;
/** Attachment subtitle */
subtitle?: string;
/** Attachment URL */
url: string;
/** Issue ID to attach to */
issueId?: string;
/** Comment ID to attach to */
commentId?: string;
/** Project update ID to attach to */
projectUpdateId?: string;
/** Icon URL for the attachment */
iconUrl?: string;
/** Metadata about the attachment */
metadata?: Record<string, unknown>;
}
interface AttachmentUpdateInput {
/** Update attachment title */
title?: string;
/** Update attachment subtitle */
subtitle?: string;
/** Update attachment URL */
url?: string;
/** Update icon URL */
iconUrl?: string;
/** Update metadata */
metadata?: Record<string, unknown>;
}Usage Examples:
// Add a file attachment to an issue
const attachment = await client.createAttachment({
title: "Design Mockup",
subtitle: "Mobile app wireframes",
url: "https://example.com/designs/mobile-mockup.fig",
issueId: "issue-id",
iconUrl: "https://example.com/icons/figma.png",
metadata: {
fileSize: "2.4MB",
fileType: "figma"
}
});
// Add screenshot to a comment
const screenshot = await client.createAttachment({
title: "Bug Screenshot",
url: "https://example.com/screenshots/bug-report.png",
commentId: "comment-id"
});
// Update attachment metadata
const updatedAttachment = await client.updateAttachment("attachment-id", {
title: "Updated Design Mockup v2",
metadata: {
version: "2.0",
lastModified: "2024-01-15"
}
});Integrate with Linear's file upload system for direct file uploads.
/**
* Get file upload URL for direct uploads
* @param input - Upload parameters
* @returns Promise resolving to upload URL and metadata
*/
fileUpload(input: FileUploadCreateInput): LinearFetch<UploadPayload>;
interface FileUploadCreateInput {
/** File content type */
contentType: string;
/** File name */
filename: string;
/** File size in bytes */
size: number;
/** Whether file is used for issue attachment */
issueId?: string;
}
interface UploadPayload {
/** The upload URL for direct upload */
uploadUrl: string;
/** Asset URL after upload */
assetUrl: string;
/** Upload headers required */
headers?: Record<string, string>;
/** Whether upload was successful */
success: boolean;
}Manage emoji reactions on comments and other content.
/**
* Create a reaction on a comment
* @param input - Reaction creation data
* @returns Promise resolving to the creation result
*/
createReaction(input: ReactionCreateInput): LinearFetch<ReactionPayload>;
/**
* Delete a reaction
* @param id - The reaction ID to delete
* @returns Promise resolving to the deletion result
*/
deleteReaction(id: string): LinearFetch<DeletePayload>;
interface ReactionCreateInput {
/** Comment ID to react to */
commentId: string;
/** Emoji for the reaction */
emoji: string;
}/** Comment model representing a comment on issues or other entities */
class Comment extends Request {
/** Unique comment identifier */
id: string;
/** Comment body in markdown */
body: string;
/** Comment body rendered as HTML */
bodyData: string;
/** Comment author */
user: User;
/** Issue this comment belongs to */
issue?: Issue;
/** Project update this comment belongs to */
projectUpdate?: ProjectUpdate;
/** Document this comment belongs to */
document?: Document;
/** Parent comment for replies */
parent?: Comment;
/** Child comments (replies) */
children: CommentConnection;
/** Attachments on this comment */
attachments: AttachmentConnection;
/** Reactions on this comment */
reactions: ReactionConnection;
/** Creation timestamp */
createdAt: DateTime;
/** Last update timestamp */
updatedAt: DateTime;
/** Last edit timestamp */
editedAt?: DateTime;
}
/** Attachment model representing a file or link attachment */
class Attachment extends Request {
/** Unique attachment identifier */
id: string;
/** Attachment title */
title?: string;
/** Attachment subtitle */
subtitle?: string;
/** Attachment URL */
url: string;
/** Icon URL */
iconUrl?: string;
/** Attachment metadata */
metadata: Record<string, unknown>;
/** Attachment creator */
creator: User;
/** Issue this attachment belongs to */
issue?: Issue;
/** Comment this attachment belongs to */
comment?: Comment;
/** Project update this attachment belongs to */
projectUpdate?: ProjectUpdate;
/** Creation timestamp */
createdAt: DateTime;
/** Last update timestamp */
updatedAt: DateTime;
}
/** Reaction model representing emoji reactions */
class Reaction extends Request {
/** Unique reaction identifier */
id: string;
/** Emoji character */
emoji: string;
/** User who created the reaction */
user: User;
/** Comment the reaction is on */
comment: Comment;
/** Creation timestamp */
createdAt: DateTime;
}
/** Response payload for comment mutations */
interface CommentPayload {
/** The mutated comment */
comment?: Comment;
/** Whether the mutation was successful */
success: boolean;
/** Last sync ID */
lastSyncId: number;
}
/** Response payload for attachment mutations */
interface AttachmentPayload {
/** The mutated attachment */
attachment?: Attachment;
/** Whether the mutation was successful */
success: boolean;
/** Last sync ID */
lastSyncId: number;
}
/** Response payload for reaction mutations */
interface ReactionPayload {
/** The mutated reaction */
reaction?: Reaction;
/** Whether the mutation was successful */
success: boolean;
/** Last sync ID */
lastSyncId: number;
}
/** Paginated connection of comments */
class CommentConnection extends Connection<Comment> {
/** Comments in this page */
nodes: Comment[];
/** Pagination information */
pageInfo: PageInfo;
}
/** Paginated connection of attachments */
class AttachmentConnection extends Connection<Attachment> {
/** Attachments in this page */
nodes: Attachment[];
/** Pagination information */
pageInfo: PageInfo;
}
/** Paginated connection of reactions */
class ReactionConnection extends Connection<Reaction> {
/** Reactions in this page */
nodes: Reaction[];
/** Pagination information */
pageInfo: PageInfo;
}Install with Tessl CLI
npx tessl i tessl/npm-linear--sdk