{"id":28799528,"url":"https://github.com/marklearst/figma-vars-hooks","last_synced_at":"2026-03-16T18:02:36.682Z","repository":{"id":299046556,"uuid":"1001039092","full_name":"marklearst/figma-vars-hooks","owner":"marklearst","description":"🌳 Welcome to FigmaVars, a React hooks library designed to simplify the integration of Figma variables into your React applications.","archived":false,"fork":false,"pushed_at":"2025-08-27T17:53:37.000Z","size":558,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-18T10:11:23.640Z","etag":null,"topics":["design-system","design-systems","design-tokens","figma","figma-api","figma-design","figma-to-code","figma-variables","react","react-hooks","react-library","storybook","storybook-design-system","typescript","typescript-library","variables-css"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/@figma-vars/hooks","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/marklearst.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-12T18:03:22.000Z","updated_at":"2025-08-28T21:56:35.000Z","dependencies_parsed_at":"2025-06-14T10:48:05.564Z","dependency_job_id":"f5a979ff-6e63-4a43-9441-1a4eb3e5fc01","html_url":"https://github.com/marklearst/figma-vars-hooks","commit_stats":null,"previous_names":["marklearst/figma-vars-hooks"],"tags_count":29,"template":false,"template_full_name":null,"purl":"pkg:github/marklearst/figma-vars-hooks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marklearst%2Ffigma-vars-hooks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marklearst%2Ffigma-vars-hooks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marklearst%2Ffigma-vars-hooks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marklearst%2Ffigma-vars-hooks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marklearst","download_url":"https://codeload.github.com/marklearst/figma-vars-hooks/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marklearst%2Ffigma-vars-hooks/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279007980,"owners_count":26084369,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-11T02:00:06.511Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["design-system","design-systems","design-tokens","figma","figma-api","figma-design","figma-to-code","figma-variables","react","react-hooks","react-library","storybook","storybook-design-system","typescript","typescript-library","variables-css"],"created_at":"2025-06-18T06:07:29.358Z","updated_at":"2026-03-16T18:02:36.669Z","avatar_url":"https://github.com/marklearst.png","language":"TypeScript","readme":"# FigmaVars/hooks\n\n\u003cp align=\"left\"\u003e\n  \u003cimg src=\"assets/figma-vars-tagline-light.png\" alt=\"FigmaVars Logo\" width=\"700px\" /\u003e\n\u003c/p\u003e\n\nBuilt and maintained by Mark Learst.\n\nA fast, typed React 19.2.3 hooks library for the Figma Variables API: fetch, update, and manage design tokens via the official [Figma REST API](https://www.figma.com/developers/api#variables).\n\nBuilt for the modern web, this library provides a suite of hooks to fetch, manage, and mutate your design tokens/variables, making it easy to sync them between Figma and your React applications, Storybooks, or design system dashboards.\n\n| Package                                                                                                               | Quality                                                                                                                                        | Activity                                                                                           |\n| --------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |\n| [![npm version](https://img.shields.io/npm/v/%40figma-vars%2Fhooks)](https://www.npmjs.com/package/@figma-vars/hooks) | ![CI](https://github.com/marklearst/figma-vars-hooks/actions/workflows/ci.yml/badge.svg)                                                       | ![GitHub last commit](https://img.shields.io/github/last-commit/marklearst/figma-vars-hooks)       |\n| ![npm downloads](https://img.shields.io/npm/dm/%40figma-vars%2Fhooks)                                                 | [![codecov](https://codecov.io/gh/marklearst/figma-vars-hooks/branch/main/graph/badge.svg)](https://codecov.io/gh/marklearst/figma-vars-hooks) | ![Status](https://img.shields.io/badge/status-stable-brightgreen)                                  |\n| ![bundle size](https://img.shields.io/bundlephobia/minzip/%40figma-vars%2Fhooks)                                      | ![Test Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen)                                                                     | ![License](https://img.shields.io/github/license/marklearst/figma-vars-hooks)                      |\n| ![node version](https://img.shields.io/node/v/%40figma-vars%2Fhooks)                                                  | ![TypeScript](https://img.shields.io/badge/TypeScript-100%25_Strict-blue?logo=typescript)                                                      | ![GitHub code size](https://img.shields.io/github/languages/code-size/marklearst/figma-vars-hooks) |\n\n## 📌 Why 4.0.0\n\n- ✨ **New Utilities**: `withRetry()` for automatic retry with exponential backoff, `redactToken()` for safe logging\n- 🔧 **Flexible API**: `baseUrl` option for fetcher/mutator, `caseInsensitive` option for filterVariables\n- 🛡️ **Better Error Handling**: Improved parsing for non-JSON API responses (HTML, plain text)\n- 🐛 **Critical Bug Fix**: SWR cache keys now correctly separate fallback and live data\n- 📚 **Improved Docs**: Comprehensive mutation return type documentation with examples\n- 📦 **Modern Tooling**: Node 20+ toolchain, strict TypeScript, and ESM-first packaging with CJS interop\n- 🖥️ **CLI Export Tool**: Automate variable exports with `figma-vars-export` for CI/CD (Enterprise required)\n\n\u003e ⚠️ **Breaking Change**: `useFigmaToken` is now a named export. See [Migration Guide](#-migration-guide-3x--40).\n\n\u003e ✅ **4.1.1 patch**: Fixed root utility exports and fallback key handling when fallback JSON is invalid.\n\n## 🚀 Features at a Glance\n\n- **Modern React 19.2 hooks** for variables, collections, modes, and published variables\n- **Ergonomic mutation hooks** with consistent loading/error states\n- **SWR configuration support** for customizing caching and revalidation behavior\n- **Error handling utilities** for type-safe error checking and status code access\n- **Cache invalidation helpers** for automatic data refresh after mutations\n- **CLI export tool** (`figma-vars-export`) for automating variable exports to JSON (Enterprise required)\n- **Fallback JSON support** (object or string) for offline/static use - works without Enterprise!\n- **Typed core entrypoint** for non-React consumers (Axios, TanStack Query, server scripts)\n- **100% test coverage** + strict TypeScript + clean exports/attw/publint/size-limit checks\n\n## 📦 Install\n\n```bash\nnpm install @figma-vars/hooks\n# or\npnpm add @figma-vars/hooks\n```\n\nPeer deps: `react` and `react-dom`.\n\n## 🖥️ CLI Export Tool\n\nThe package includes a **CLI tool** (`figma-vars-export`) for automatically exporting Figma variables to JSON via the REST API. Perfect for CI/CD pipelines, build scripts, or one-off exports.\n\n\u003e ⚠️ **Enterprise Required**: The CLI tool uses the Figma Variables REST API, which requires a **Figma Enterprise account**. Without Enterprise, use the [Dev Mode plugin export](#exporting-variables-for-fallback) method instead.\n\n```bash\n# Using npx (no install needed)\nFIGMA_TOKEN=your_token npx figma-vars-export --file-key YOUR_FILE_KEY --out ./variables.json\n\n# After installing\nnpm install @figma-vars/hooks\nFIGMA_TOKEN=your_token figma-vars-export --file-key YOUR_FILE_KEY --out ./variables.json\n\n# Show help\nfigma-vars-export --help\n```\n\n**Options:**\n\n- `--file-key` - Figma file key (required, or set `FIGMA_FILE_KEY` env var)\n- `--out` - Output path (default: `data/figma-variables.json`)\n- `--help` - Show help message\n\n**Environment Variables:**\n\n- `FIGMA_TOKEN` or `FIGMA_PAT` - Figma Personal Access Token (required)\n- `FIGMA_FILE_KEY` - Figma file key (optional)\n\n**Example Output:**\n\n```\nSaved variables to ./variables.json\nVariables count: 42\n```\n\n**No Enterprise?** See [Exporting variables for fallback](#exporting-variables-for-fallback) for alternative methods that work without Enterprise.\n\n## 🛠️ Quick Start (SWR-powered hooks)\n\n```tsx\nimport { FigmaVarsProvider, useVariables } from '@figma-vars/hooks'\n\nconst FIGMA_TOKEN = import.meta.env.VITE_FIGMA_TOKEN\nconst FIGMA_FILE_KEY = 'your-file-key'\n\nfunction App() {\n  return (\n    \u003cFigmaVarsProvider\n      token={FIGMA_TOKEN}\n      fileKey={FIGMA_FILE_KEY}\n      swrConfig={{\n        revalidateOnFocus: false,\n        dedupingInterval: 5000,\n      }}\u003e\n      \u003cTokens /\u003e\n    \u003c/FigmaVarsProvider\u003e\n  )\n}\n\nfunction Tokens() {\n  const { data, isLoading, error } = useVariables()\n  if (isLoading) return \u003cdiv\u003eLoading…\u003c/div\u003e\n  if (error) return \u003cdiv\u003eError: {error.message}\u003c/div\u003e\n  const variables = Object.values(data?.meta.variables ?? {})\n  return \u003cpre\u003e{JSON.stringify(variables, null, 2)}\u003c/pre\u003e\n}\n```\n\n## 🧩 Non-SWR Usage (Core entrypoint)\n\nUse the `/core` build when you prefer Axios/TanStack/server scripts without React/SWR.\n\n**Axios example (GET + bulk PUT)**\n\n```ts\nimport axios from 'axios'\nimport { FIGMA_FILE_VARIABLES_PATH } from '@figma-vars/hooks/core'\n\nconst token = process.env.FIGMA_TOKEN!\nconst fileKey = process.env.FIGMA_FILE_KEY!\n\n// Fetch local variables\nconst url = `https://api.figma.com${FIGMA_FILE_VARIABLES_PATH(fileKey)}/local`\nconst { data } = await axios.get(url, {\n  headers: { 'X-FIGMA-TOKEN': token, 'Content-Type': 'application/json' },\n})\n\n// Bulk update\nawait axios.put(\n  `https://api.figma.com${FIGMA_FILE_VARIABLES_PATH(fileKey)}`,\n  { variables: [{ action: 'UPDATE', id: 'VariableId:123', name: 'new-name' }] },\n  { headers: { 'X-FIGMA-TOKEN': token, 'Content-Type': 'application/json' } }\n)\n```\n\n**TanStack Query example**\n\n```ts\nimport { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'\nimport { FIGMA_FILE_VARIABLES_PATH, fetcher, mutator } from '@figma-vars/hooks/core'\n\nconst token = process.env.FIGMA_TOKEN!\nconst fileKey = process.env.FIGMA_FILE_KEY!\n\nexport function useLocalVariables() {\n  return useQuery({\n    queryKey: ['figma-local', fileKey],\n    queryFn: () =\u003e fetcher(`${FIGMA_FILE_VARIABLES_PATH(fileKey)}/local`, token),\n    staleTime: 60_000,\n  })\n}\n\nexport function useBulkUpdate() {\n  const qc = useQueryClient()\n  return useMutation({\n    mutationFn: (payload: unknown) =\u003e\n      mutator(FIGMA_FILE_VARIABLES_PATH(fileKey), token, 'UPDATE', payload),\n    onSuccess: () =\u003e qc.invalidateQueries({ queryKey: ['figma-local', fileKey] }),\n  })\n}\n```\n\n## 🛡️ Fallback JSON (offline/static)\n\nPass `fallbackFile` (object or JSON string) to `FigmaVarsProvider` to bypass live API calls:\n\n```tsx\nimport exportedVariables from './figma-variables.json'\n;\u003cFigmaVarsProvider\n  token={null}\n  fileKey={null}\n  fallbackFile={exportedVariables}\u003e\n  \u003cApp /\u003e\n\u003c/FigmaVarsProvider\u003e\n```\n\n### Exporting variables for fallback\n\nThere are several ways to get your Figma variables as JSON:\n\n1. **Dev Mode / plugin export (recommended, no Enterprise needed)** ⭐\n   - Use a Variables exporter plugin in Figma Dev Mode to download the full Variables panel as JSON\n   - Save anywhere (e.g., `data/figma-variables.json`) and pass it to `fallbackFile`\n   - Works for everyone, no Enterprise account required!\n\n2. **CLI export tool (Enterprise required)** 🚀\n   - Automatically exports via REST API - perfect for CI/CD and automation\n   - See the [CLI Export Tool](#-cli-export-tool) section above for full usage details\n   - Also available from cloned repo: `node scripts/export-variables.mjs --file-key KEY --out file.json`\n\n- **Desktop MCP (manual/partial)**: Selecting a frame and running `get_variable_defs` returns only that selection’s variables. Use plugin/REST exports for complete coverage.\n\n4. **Style Dictionary**\n   - Once you have the JSON (from any path), feed it into Style Dictionary to emit platform-specific artifacts\n   - Or import it directly via `fallbackFile`\n\n## 🔧 Mutation Hooks (verbs fixed)\n\n- `useCreateVariable` → POST via bulk endpoint with `action: 'CREATE'`\n- `useUpdateVariable` → PUT via bulk endpoint with `action: 'UPDATE'`\n- `useDeleteVariable` → DELETE via bulk endpoint with `action: 'DELETE'`\n- `useBulkUpdateVariables` → PUT bulk payload (collections, modes, variables, values)\n\nAll return `{ mutate, data, error, isLoading, isSuccess, isError }`.\n\n### Example: Creating and updating variables\n\n```tsx\nimport { useCreateVariable, useUpdateVariable, useInvalidateVariables } from '@figma-vars/hooks'\n\nfunction VariableEditor() {\n  const { mutate: create } = useCreateVariable()\n  const { mutate: update } = useUpdateVariable()\n  const { invalidate } = useInvalidateVariables()\n\n  const handleCreate = async () =\u003e {\n    await create({\n      name: 'Primary Color',\n      variableCollectionId: 'CollectionId:123',\n      resolvedType: 'COLOR',\n    })\n    invalidate() // Refresh cache after mutation\n  }\n\n  const handleUpdate = async (id: string) =\u003e {\n    await update({\n      variableId: id,\n      payload: { name: 'Updated Name' },\n    })\n    invalidate() // Refresh cache after mutation\n  }\n\n  return (\n    \u003c\u003e\n      \u003cbutton onClick={handleCreate}\u003eCreate Variable\u003c/button\u003e\n      \u003cbutton onClick={() =\u003e handleUpdate('VariableId:123')}\u003eUpdate\u003c/button\u003e\n    \u003c/\u003e\n  )\n}\n```\n\n## 🛡️ Error Handling\n\n### Error Boundaries (Recommended)\n\nWrap your Figma-connected components with an error boundary to gracefully handle errors:\n\n```tsx\nimport { ErrorBoundary } from 'react-error-boundary'\nimport { FigmaVarsProvider } from '@figma-vars/hooks'\n\nfunction FigmaErrorFallback({ error }: { error: Error }) {\n  return (\n    \u003cdiv role='alert'\u003e\n      \u003ch2\u003eFailed to load Figma data\u003c/h2\u003e\n      \u003cpre\u003e{error.message}\u003c/pre\u003e\n    \u003c/div\u003e\n  )\n}\n\nfunction App() {\n  return (\n    \u003cErrorBoundary FallbackComponent={FigmaErrorFallback}\u003e\n      \u003cFigmaVarsProvider\n        token={FIGMA_TOKEN}\n        fileKey={FIGMA_FILE_KEY}\u003e\n        \u003cYourApp /\u003e\n      \u003c/FigmaVarsProvider\u003e\n    \u003c/ErrorBoundary\u003e\n  )\n}\n```\n\n\u003e **Note:** The provider validates fallback file structure at runtime and logs warnings in development. Invalid fallback data won't crash the app but will result in `undefined` data.\n\n### Runtime Validation\n\nUse type guards to validate data at runtime:\n\n```tsx\nimport { isLocalVariablesResponse, isPublishedVariablesResponse } from '@figma-vars/hooks'\n\n// Validate before using\nif (isLocalVariablesResponse(data)) {\n  // Safe to access data.meta.variables\n}\n```\n\n### Error Utilities\n\nThe library includes powerful error handling utilities for type-safe error checking:\n\n```tsx\nimport { isFigmaApiError, getErrorStatus, getErrorMessage, hasErrorStatus } from '@figma-vars/hooks'\n\nfunction ErrorHandler({ error }: { error: Error | null }) {\n  if (!error) return null\n\n  // Type guard for FigmaApiError\n  if (isFigmaApiError(error)) {\n    const status = error.statusCode\n\n    if (status === 401) {\n      return \u003cdiv\u003eAuthentication required. Please check your token.\u003c/div\u003e\n    }\n    if (status === 403) {\n      return \u003cdiv\u003eAccess forbidden. Check file permissions.\u003c/div\u003e\n    }\n    if (status === 429) {\n      return \u003cdiv\u003eRate limit exceeded. Please wait before retrying.\u003c/div\u003e\n    }\n    if (status === 404) {\n      return \u003cdiv\u003eFile or variable not found.\u003c/div\u003e\n    }\n  }\n\n  // Helper functions\n  const status = getErrorStatus(error) // number | null\n  const message = getErrorMessage(error) // string\n\n  // Convenience check\n  if (hasErrorStatus(error, 401)) {\n    // Handle unauthorized\n  }\n\n  return \u003cdiv\u003eError: {message}\u003c/div\u003e\n}\n```\n\n**Common HTTP Status Codes:**\n\n- `401` - Unauthorized (invalid or missing token)\n- `403` - Forbidden (insufficient permissions)\n- `404` - Not Found (file/variable doesn't exist)\n- `429` - Too Many Requests (rate limit exceeded)\n\n## 🔄 Cache Management\n\nAfter mutations, use `useInvalidateVariables` to refresh cached data:\n\n```tsx\nimport { useUpdateVariable, useInvalidateVariables } from '@figma-vars/hooks'\n\nfunction UpdateButton({ variableId }: { variableId: string }) {\n  const { mutate, isLoading } = useUpdateVariable()\n  const { invalidate, revalidate } = useInvalidateVariables()\n\n  const handleUpdate = async () =\u003e {\n    await mutate({\n      variableId,\n      payload: { name: 'New Name' },\n    })\n\n    // Option 1: Invalidate (refetch on next access)\n    invalidate()\n\n    // Option 2: Revalidate immediately (refetch now)\n    // revalidate()\n  }\n\n  return (\n    \u003cbutton\n      onClick={handleUpdate}\n      disabled={isLoading}\u003e\n      {isLoading ? 'Updating...' : 'Update Variable'}\n    \u003c/button\u003e\n  )\n}\n```\n\n## ⚙️ SWR Configuration\n\nCustomize SWR behavior globally through the provider:\n\n```tsx\n\u003cFigmaVarsProvider\n  token={FIGMA_TOKEN}\n  fileKey={FIGMA_FILE_KEY}\n  swrConfig={{\n    revalidateOnFocus: false, // Don't refetch on window focus\n    dedupingInterval: 5000, // Dedupe requests within 5s\n    errorRetryCount: 3, // Retry failed requests 3 times\n    errorRetryInterval: 1000, // Wait 1s between retries\n    onError: error =\u003e {\n      // Global error handler\n      if (isFigmaApiError(error) \u0026\u0026 error.statusCode === 429) {\n        console.warn('Rate limited, backing off...')\n      }\n    },\n  }}\u003e\n  \u003cApp /\u003e\n\u003c/FigmaVarsProvider\u003e\n```\n\n**Common SWR Options:**\n\n- `revalidateOnFocus` - Refetch when window regains focus (default: `true`)\n- `dedupingInterval` - Deduplication interval in ms (default: `2000`)\n- `errorRetryCount` - Max retry attempts (default: `5`)\n- `refreshInterval` - Polling interval in ms (default: `0` = disabled)\n- `onError` - Global error callback\n\n## 📚 API Cheat Sheet\n\n### Hooks\n\n- **Queries**: `useVariables` (local), `usePublishedVariables` (library/published), `useVariableCollections`, `useVariableModes`, `useFigmaToken`\n- **Granular Selectors**: `useCollectionById`, `useModesByCollection`, `useVariableById` (optimized selectors for specific entities)\n- **Mutations**: `useCreateVariable`, `useUpdateVariable`, `useDeleteVariable`, `useBulkUpdateVariables`\n- **Cache**: `useInvalidateVariables` (invalidate/revalidate cache)\n\n### Utilities\n\n- **Filtering**: `filterVariables` (filter by type, name, with optional `caseInsensitive` matching)\n- **Retry**: `withRetry` (automatic retry with exponential backoff for rate limits)\n- **Security**: `redactToken` (safely redact tokens for logging/display)\n- **Error Handling**: `isFigmaApiError`, `getErrorStatus`, `getErrorMessage`, `hasErrorStatus`, `isRateLimited`, `getRetryAfter`\n- **Type Guards**: `isLocalVariablesResponse`, `isPublishedVariablesResponse`, `validateFallbackData` (runtime validation)\n- **SWR Keys**: `getVariablesKey`, `getPublishedVariablesKey`, `getInvalidationKeys` (centralized cache key construction)\n- **Core helpers**: `fetcher`, `mutator` (with `baseUrl` option), constants for endpoints and headers\n\n### Types\n\n- **Responses**: `LocalVariablesResponse`, `PublishedVariablesResponse`\n- **Variables**: `FigmaVariable`, `FigmaCollection`, `VariableMode`\n- **Mutations**: `BulkUpdatePayload`, `CreateVariablePayload`, `UpdateVariablePayload`\n- **Errors**: `FigmaApiError` (extends `Error` with `statusCode`)\n\n## 🔐 Auth \u0026 Scope\n\n- Header: `X-FIGMA-TOKEN: \u003cPAT\u003e`\n- Scopes: `file_variables:read` for GETs, `file_variables:write` for mutations.\n- Enterprise Full seat required for live API; fallback JSON works without a token.\n\n## ⚠️ Enterprise Requirement and Offline Options\n\n- The Figma Variables REST API requires a Figma Enterprise seat for live requests. Without Enterprise, live calls will fail even with a valid PAT.\n- The library remains useful without Enterprise: supply `fallbackFile` (object or JSON string) exported from Figma (Dev Mode plugin, CLI, or Figma MCP server output) and all read hooks work offline/for static deployments.\n- MCP/other exporters: as long as they emit the same JSON shape as the Variables API, you can feed that JSON into `fallbackFile`; mutations still require Enterprise access.\n\n## 🚫 Do Not Publish Tokens or File Keys\n\n- Never commit PATs or file keys to git, Storybook static builds, or client bundles.\n- Use environment variables (`process.env` / `import.meta.env`) and secret managers; keep them server-side where possible.\n- Prefer `fallbackFile` with `token={null}`/`fileKey={null}` for demos and public Storybooks.\n- Use `redactToken()` when logging tokens for debugging:\n\n```ts\nimport { redactToken } from '@figma-vars/hooks'\n\n// Safe logging\nconsole.log('Using token:', redactToken(token))\n// Output: \"Using token: figd_***...***cret\"\n```\n\n## 📈 Rate Limits\n\n- Figma enforces per-token limits. Rely on SWR/TanStack caching, avoid unnecessary refetches, and prefer fallback JSON for static sites.\n- Use `swrConfig` to customize `dedupingInterval` and `errorRetryCount` to optimize API usage.\n- Use `withRetry()` utility for automatic retry with exponential backoff on 429 errors:\n\n```ts\nimport { withRetry, fetcher } from '@figma-vars/hooks'\n\nconst fetchWithRetry = withRetry(() =\u003e fetcher('/v1/files/KEY/variables/local', token), {\n  maxRetries: 3,\n  onRetry: (attempt, delay) =\u003e console.log(`Retry ${attempt}...`),\n})\n```\n\n## 📚 Storybook \u0026 Next.js\n\n- **Storybook decorator**: wrap stories once so hooks have context and tokens.\n\n```tsx\n// .storybook/preview.tsx\nimport { FigmaVarsProvider } from '@figma-vars/hooks'\nimport type { Preview } from '@storybook/react'\n\nconst FIGMA_TOKEN = process.env.STORYBOOK_FIGMA_TOKEN\nconst FIGMA_FILE_KEY = process.env.STORYBOOK_FIGMA_FILE_KEY\n\nconst preview: Preview = {\n  decorators: [\n    Story =\u003e (\n      \u003cFigmaVarsProvider\n        token={FIGMA_TOKEN}\n        fileKey={FIGMA_FILE_KEY}\u003e\n        \u003cStory /\u003e\n      \u003c/FigmaVarsProvider\u003e\n    ),\n  ],\n}\n\nexport default preview\n```\n\n- **Next.js App Router**: provide context in a shared provider file.\n\n```tsx\n// app/providers.tsx\nimport { FigmaVarsProvider } from '@figma-vars/hooks'\n\nexport function Providers({ children }: { children: React.ReactNode }) {\n  return (\n    \u003cFigmaVarsProvider\n      token={process.env.NEXT_PUBLIC_FIGMA_TOKEN}\n      fileKey={process.env.NEXT_PUBLIC_FIGMA_FILE_KEY}\u003e\n      {children}\n    \u003c/FigmaVarsProvider\u003e\n  )\n}\n```\n\n## 🧪 Tooling \u0026 Quality Gates\n\n- `pnpm run build`, `pnpm test`, `pnpm run test:coverage`\n- `pnpm run check:publint`, `pnpm run check:attw`, `pnpm run check:size`\n\n## 🧭 Release Checklist (4.x)\n\n- Run `pnpm run check:release`\n- Bump the version with `pnpm version patch|minor|major` (creates matching git tag, e.g. `v4.1.1`)\n- Push commit + tags (`git push \u0026\u0026 git push --tags`) so release workflows can run\n- CI publishes to npm automatically\n- Update dist-tags on npm if needed (`latest` → current stable)\n\n**Backfill tags if missing:**\n\n```bash\ngit tag -a v4.1.0 \u003ccommit-sha-for-4.1.0\u003e -m \"v4.1.0\"\ngit tag -a v4.1.1 \u003ccommit-sha-for-4.1.1\u003e -m \"v4.1.1\"\ngit push --tags\n```\n\n## 🔄 Migration Guide (3.x → 4.0)\n\n### Breaking Change: `useFigmaToken` Export\n\n```tsx\n// Before (3.x) - NO LONGER WORKS\nimport useFigmaToken from '@figma-vars/hooks'\n\n// After (4.0) - USE THIS\nimport { useFigmaToken } from '@figma-vars/hooks'\n```\n\n### New Utilities (opt-in)\n\n```ts\nimport { withRetry, redactToken, filterVariables } from '@figma-vars/hooks'\n\n// Automatic retry with exponential backoff\nconst fetchWithRetry = withRetry(() =\u003e myApiCall(), { maxRetries: 3 })\n\n// Safe token logging\nconsole.log('Token:', redactToken(token)) // \"figd_***...***cret\"\n\n// Case-insensitive filtering\nfilterVariables(vars, { name: 'primary', caseInsensitive: true })\n```\n\n### Custom API Base URL\n\n```ts\nimport { fetcher, mutator } from '@figma-vars/hooks/core'\n\n// Use mock server for testing\nawait fetcher('/v1/files/KEY/variables/local', token, {\n  baseUrl: 'http://localhost:3000',\n})\n```\n\n---\n\n## 📝 Contributing\n\nPRs and issues are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\n## 📝 License\n\nThis project is licensed under the [MIT License](LICENSE).\n© 2024–2026 Mark Learst\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarklearst%2Ffigma-vars-hooks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarklearst%2Ffigma-vars-hooks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarklearst%2Ffigma-vars-hooks/lists"}