@kody/figma
README.md
239 lines · 8.6 KB · Markdown@kody/figma
Intent
Provide reusable, account-agnostic Figma REST helpers so Kody agents can read
files, nodes, comments, components, styles, and images through a saved
figma / figma-* OAuth integration or a personal/plan access token — without
hand-rolling REST. Comment and other write mutations are previewable with
dryRun: true and only run live after confirm: true.
This listing is meant to be forked. After you fork, connect your Figma
account. Do not treat the live @kody/figma package storage as yours.
Share this listing as https://kody.codes/@kody/figma
When To Use
- Inspect a Figma file, specific nodes, or file metadata
- List, preview, or (after confirmation) create/delete comments
- List published components and styles
- Render node images or list image-fill download URLs
- Call an unwrapped Figma REST path through
./request - Connect more than one Figma account via
integrationName/account
Auth
Figma has no built-in Kody OAuth app. Choose one lane:
| Lane | When to use | Credential |
|---|---|---|
| OAuth (recommended) | Multi-account, refresh tokens, shared helpers | Saved integration figma or figma-<purpose> |
| Personal or plan access token | Fastest for a single account / scripts | User secret figmaPat (or figmaPat-<purpose>) |
OAuth sends Authorization: Bearer …. Tokens send X-Figma-Token. Required
API host: api.figma.com. Approve it in the account secrets UI.
Lane A — BYO OAuth
- Create an OAuth app at https://www.figma.com/developers/apps
- Set the redirect URI exactly to
https://kody.codes/connect/oauth - Enable the scopes this package uses (
current_user:read,file_content:read,file_metadata:read,file_comments:read,file_comments:write,file_versions:read,library_content:read,library_assets:read,projects:read). - Connect while signed in to Kody:
- Paste the Figma client id and client secret into the Kody wizard (never into
chat). Approve host
api.figma.com. - Reconnect later with https://kody.codes/connect/oauth?provider=figma
OAuth authorize URL: https://www.figma.com/oauth. Token URL:
https://api.figma.com/v1/oauth/token. Flow: confidential (client secret) plus
S256 PKCE. Figma scopes are space-separated (commas also work at Figma).
To connect a second account, change provider (for example
provider=figma-work) and pass integrationName: 'figma-work' on every call.
Lane B — Personal or plan access token
- Create a personal access token from Figma Settings → Security, or a plan token at https://www.figma.com/developers/tokens (PAT docs)
- Save it (do not paste the value in chat):
For a second account/token, use a distinct secret name such as figmaPat-work
and pass secretName: 'figmaPat-work' (or account: 'work', which resolves to
figma-work / figmaPat-work).
Scopes
| Scope | Needed for |
|---|---|
current_user:read | ./viewer, ./smoke-test |
file_content:read | ./get-file, ./get-file-nodes, ./get-images, ./get-image-fills |
file_metadata:read | ./get-file-meta |
file_comments:read | ./list-comments |
file_comments:write | ./create-comment, ./delete-comment |
file_versions:read | Versioned reads via ./request |
library_content:read | ./list-file-components, ./list-file-styles |
library_assets:read | Library image assets via ./request |
projects:read | Team/project listing via ./request |
If Figma returns 401/403 or an insufficient-scope error, helpers throw a message that names the missing scope and the next setup URL (reconnect OAuth with that scope, or save a token).
Multiple accounts
Every export accepts:
integrationName/integration— exact saved OAuth name (figma-work)account—work→figma-work;figma-workused as-is; omitted →figmasecretName— token secret overrideauth—'oauth'or'pat'when both exist
Do not hard-code a personal file key or team id.
Safety
Mutating helpers (./create-comment, ./delete-comment, and mutating
./request methods) require confirm: true. Pass dryRun: true to inspect
the REST payload without calling Figma. ./request treats GET as read-only;
POST / PUT / PATCH / DELETE need confirmation.
Exports
| Export | Description |
|---|---|
. | Package overview, connect URLs, export map |
./accounts | Resolve integration/secret names and report what is connected |
./smoke-test | Local helper checks plus optional live viewer read (no email) |
./viewer | Authenticated user id / handle |
./get-file | Slim file JSON (defaults to depth: 1) |
./get-file-nodes | Slim JSON for specific nodes |
./get-file-meta | File metadata without the document tree |
./list-comments | Comments on a file |
./create-comment | Preview or create a comment |
./delete-comment | Preview or delete a comment |
./list-file-components | Published components in a file |
./list-file-styles | Published styles in a file |
./get-images | Rendered node image URLs |
./get-image-fills | Image-fill download URLs |
./request | Generic REST escape hatch |
./types | Shared TypeScript types |
Smoke test
import smokeTest from 'kody:@kody/figma/smoke-test'
export default async function main() {
return await smokeTest()
}Without credentials this returns { ok: true, live: false } plus the connect
and token URLs. After OAuth or a token is saved it reads /v1/me and returns
{ live: true, hasViewerId } without email.
Root import:
import figma from 'kody:@kody/figma'
export default async function main() {
return await figma()
}Preview a mutation without credentials:
import createComment from 'kody:@kody/figma/create-comment'
export default async function main() {
return await createComment({
fileKey: 'abc123',
message: 'Ship the new empty state.',
dryRun: true,
})
}Examples
import getFile from 'kody:@kody/figma/get-file'
import listComments from 'kody:@kody/figma/list-comments'
export default async function main() {
const file = await getFile({
fileKey: 'https://www.figma.com/design/abc123/Checkout',
})
return {
file,
comments: await listComments({ fileKey: file.fileKey }),
}
}import createComment from 'kody:@kody/figma/create-comment'
export default async function main() {
const preview = await createComment({
fileKey: 'abc123',
message: 'Please bump the empty-state type to 16.',
nodeId: '12:34',
dryRun: true,
})
// After the user confirms the exact file and message:
return await createComment({
fileKey: 'abc123',
message: 'Please bump the empty-state type to 16.',
nodeId: '12:34',
confirm: true,
})
}Unwrapped REST:
import request from 'kody:@kody/figma/request'
export default async function main() {
return await request({
path: '/v1/me',
})
}Notes
- REST base:
https://api.figma.com fileKeyaccepts a raw key or afigma.comfile/design/board/proto URL- Node ids from Figma URLs (
1-2) are normalized to API form (1:2) ./get-fileprojects a slim document (id/name/type/children) so agents do not pull full vector trees by default- Use
./requestfor team projects, versions, webhooks, variables, or other unwrapped paths - This package is not affiliated with or endorsed by Figma, Inc.
Branding
The community icon is Figma's official five-shape logomark (red, orange, purple, blue, green). Paths are unmodified from the official mark. Figma® is a trademark of Figma, Inc.