@frontfriend/tailwind 4.0.17 → 4.0.19

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.
Files changed (42) hide show
  1. package/dist/browser.mjs +1 -1
  2. package/dist/browser.mjs.map +3 -3
  3. package/dist/cli.js +39 -47
  4. package/dist/component-recipes.d.ts +14 -0
  5. package/dist/components-config-schema.js +1 -1
  6. package/dist/components-config-schema.js.map +3 -3
  7. package/dist/ffdc.d.ts +11 -1
  8. package/dist/ffdc.js +1 -1
  9. package/dist/ffdc.js.map +4 -4
  10. package/dist/index.js +3 -3
  11. package/dist/index.js.map +4 -4
  12. package/dist/index.mjs +1 -1
  13. package/dist/index.mjs.map +3 -3
  14. package/dist/lib/core/api-client.js +2 -2
  15. package/dist/lib/core/api-client.js.map +3 -3
  16. package/dist/lib/core/cache-manager.js +4 -3
  17. package/dist/lib/core/cached-components-config.js +2 -0
  18. package/dist/lib/core/cached-components-config.js.map +7 -0
  19. package/dist/lib/core/component-downloader.js +2 -2
  20. package/dist/lib/core/component-downloader.js.map +3 -3
  21. package/dist/lib/core/component-recipes.js +8 -0
  22. package/dist/lib/core/component-recipes.js.map +7 -0
  23. package/dist/lib/core/components-config-schema.js +1 -1
  24. package/dist/lib/core/components-config-schema.js.map +3 -3
  25. package/dist/next.js +1 -1
  26. package/dist/next.js.map +4 -4
  27. package/dist/runtime.js +1 -1
  28. package/dist/runtime.js.map +3 -3
  29. package/dist/types/index.d.ts +15 -1
  30. package/dist/vite.js +6 -19
  31. package/dist/vite.js.map +4 -4
  32. package/dist/vite.mjs +4 -4
  33. package/dist/vite.mjs.map +3 -3
  34. package/package.json +7 -1
  35. package/scripts/build.js +32 -9
  36. package/src/theme.css +3 -9
  37. package/dist/lib/core/default-config-data.js +0 -2
  38. package/dist/lib/core/default-config-data.js.map +0 -7
  39. package/dist/lib/core/default-config.js +0 -2
  40. package/dist/lib/core/default-config.js.map +0 -7
  41. package/scripts/master-components-config.json +0 -1678
  42. package/scripts/update-default-config-data.js +0 -891
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import{createRequire as u}from"module";var _=u(import.meta.url),{componentsConfigSchema:F,isCSSClassString:l}=_("./lib/core/components-config-schema.js"),s=typeof window<"u"&&typeof window.document<"u",i=typeof process<"u"&&process.versions&&process.versions.node,o=null,f=i?function(...n){if(!o)try{o=_("module").createRequire(import.meta.url)("./index.js")}catch(e){return console.error("[FrontFriend] Failed to load plugin:",e),{}}return typeof o=="function"?o(...n):o}:function(){return s&&console.warn("[FrontFriend] The Tailwind plugin cannot be used directly in browser environments"),{}};function c(){let n=new Map,e={get(t,r){return r===Symbol.toPrimitive||r==="valueOf"?()=>"":r==="toString"||r===Symbol.toStringTag?()=>"":r==="constructor"?Object:(n.has(r)||n.set(r,c()),n.get(r))},has(t,r){return!(typeof r=="symbol"&&r.toString().includes("nodejs.util.inspect"))},ownKeys(t){return[]},getOwnPropertyDescriptor(t,r){return{enumerable:!0,configurable:!0}}};return new Proxy({},e)}function d(n){return!n||typeof n!="object"?c():n}var g=new Proxy({},{_cjsConfig:null,_proxyCache:new Map,get(n,e){if(e===Symbol.toPrimitive||e==="valueOf")return()=>"";if(e==="toString"||e===Symbol.toStringTag)return()=>"[object Object]";if(e==="constructor")return Object;if(i&&!this._cjsConfig&&o&&(this._cjsConfig=o.config),i&&this._cjsConfig&&e in this._cjsConfig)return this._cjsConfig[e];let t=null;if(typeof __FF_CONFIG__<"u")t=__FF_CONFIG__;else if(typeof process<"u"&&process.env){if(process.env.NEXT_PUBLIC_FF_CONFIG)try{t=JSON.parse(process.env.NEXT_PUBLIC_FF_CONFIG)}catch{console.warn("[FrontFriend] Failed to parse NEXT_PUBLIC_FF_CONFIG")}else if(process.env.__FF_CONFIG__)try{t=JSON.parse(process.env.__FF_CONFIG__)}catch{console.warn("[FrontFriend] Failed to parse __FF_CONFIG__")}}else s&&window.__FF_CONFIG__&&(t=window.__FF_CONFIG__);return t&&e in t?t[e]:(this._proxyCache.has(e)||this._proxyCache.set(e,c()),this._proxyCache.get(e))},has(n,e){return!0},ownKeys(n){return[]},getOwnPropertyDescriptor(n,e){return{enumerable:!0,configurable:!0}}}),S=new Proxy({},{_cjsIconSet:null,get(n,e){if(e===Symbol.toPrimitive||e==="valueOf")return()=>"";if(e==="toString"||e===Symbol.toStringTag)return()=>"[object Object]";if(e==="constructor")return Object;if(i&&!this._cjsIconSet&&o&&(this._cjsIconSet=o.iconSet),i&&this._cjsIconSet&&e in this._cjsIconSet)return this._cjsIconSet[e];let t=null;if(typeof __FF_ICONS__<"u")t=__FF_ICONS__;else if(typeof process<"u"&&process.env){if(process.env.NEXT_PUBLIC_FF_ICONS)try{t=JSON.parse(process.env.NEXT_PUBLIC_FF_ICONS)}catch{console.warn("[FrontFriend] Failed to parse NEXT_PUBLIC_FF_ICONS")}else if(process.env.__FF_ICONS__)try{t=JSON.parse(process.env.__FF_ICONS__)}catch{console.warn("[FrontFriend] Failed to parse __FF_ICONS__")}}else s&&window.__FF_ICONS__&&(t=window.__FF_ICONS__);return t&&e in t?t[e]:null},has(n,e){return!1},ownKeys(n){return[]},getOwnPropertyDescriptor(n,e){}});var C=f;export{F as componentsConfigSchema,g as config,C as default,d as ffdc,S as iconSet,l as isCSSClassString};
1
+ import{createRequire as d}from"module";var f=d(import.meta.url),{componentsConfigSchema:S,isCSSClassString:O}=f("./lib/core/components-config-schema.js"),_=typeof window<"u"&&typeof window.document<"u",s=typeof process<"u"&&process.versions&&process.versions.node,i=null,y=s?function(...t){if(!i)try{i=f("module").createRequire(import.meta.url)("./index.js")}catch(e){return console.error("[FrontFriend] Failed to load plugin:",e),{}}return typeof i=="function"?i(...t):i}:function(){return _&&console.warn("[FrontFriend] The Tailwind plugin cannot be used directly in browser environments"),{}};function u(){let t=new Map,e={get(n,r){return r===Symbol.toPrimitive||r==="valueOf"?()=>"":r==="toString"||r===Symbol.toStringTag?()=>"":r==="constructor"?Object:(t.has(r)||t.set(r,u()),t.get(r))},has(n,r){return!(typeof r=="symbol"&&r.toString().includes("nodejs.util.inspect"))},ownKeys(n){return[]},getOwnPropertyDescriptor(n,r){return{enumerable:!0,configurable:!0}}};return new Proxy({},e)}function c(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)}function a(t,e){if(!c(t)||!c(e))return e===void 0?t:e;let n={...t};for(let[r,o]of Object.entries(e))n[r]=r in n?a(n[r],o):o;return n}function l(t,e,n=[],r=[]){if(t===void 0||e===void 0)return r;if(!c(t)||!c(e))return r.push(n.join(".")),r;for(let o of Object.keys(t))o in e&&l(t[o],e[o],[...n,o],r);return r}function F(t,e=[]){if(!c(t)||!("styles"in t||"behavior"in t))return t;let n=l(t.styles,t.behavior,e);if(n.length>0)throw new Error(`Component config styles/behavior conflict at ${n.join(", ")}`);return a(t.styles||{},t.behavior||{})}function g(t){let e=!1,n={};for(let[r,o]of Object.entries(t))n[r]=F(o,[r]),n[r]!==o&&(e=!0);return e?n:t}function h(t){return!t||typeof t!="object"?u():g(t)}var m=new Proxy({},{_cjsConfig:null,_proxyCache:new Map,get(t,e){if(e===Symbol.toPrimitive||e==="valueOf")return()=>"";if(e==="toString"||e===Symbol.toStringTag)return()=>"[object Object]";if(e==="constructor")return Object;if(s&&!this._cjsConfig&&i&&(this._cjsConfig=i.config),s&&this._cjsConfig&&e in this._cjsConfig)return this._cjsConfig[e];let n=null;if(typeof __FF_CONFIG__<"u")n=__FF_CONFIG__;else if(typeof process<"u"&&process.env){if(process.env.NEXT_PUBLIC_FF_CONFIG)try{n=JSON.parse(process.env.NEXT_PUBLIC_FF_CONFIG)}catch{console.warn("[FrontFriend] Failed to parse NEXT_PUBLIC_FF_CONFIG")}else if(process.env.__FF_CONFIG__)try{n=JSON.parse(process.env.__FF_CONFIG__)}catch{console.warn("[FrontFriend] Failed to parse __FF_CONFIG__")}}else _&&window.__FF_CONFIG__&&(n=window.__FF_CONFIG__);return n&&e in n?F(n[e],[String(e)]):(this._proxyCache.has(e)||this._proxyCache.set(e,u()),this._proxyCache.get(e))},has(t,e){return!0},ownKeys(t){return[]},getOwnPropertyDescriptor(t,e){return{enumerable:!0,configurable:!0}}}),w=new Proxy({},{_cjsIconSet:null,get(t,e){if(e===Symbol.toPrimitive||e==="valueOf")return()=>"";if(e==="toString"||e===Symbol.toStringTag)return()=>"[object Object]";if(e==="constructor")return Object;if(s&&!this._cjsIconSet&&i&&(this._cjsIconSet=i.iconSet),s&&this._cjsIconSet&&e in this._cjsIconSet)return this._cjsIconSet[e];let n=null;if(typeof __FF_ICONS__<"u")n=__FF_ICONS__;else if(typeof process<"u"&&process.env){if(process.env.NEXT_PUBLIC_FF_ICONS)try{n=JSON.parse(process.env.NEXT_PUBLIC_FF_ICONS)}catch{console.warn("[FrontFriend] Failed to parse NEXT_PUBLIC_FF_ICONS")}else if(process.env.__FF_ICONS__)try{n=JSON.parse(process.env.__FF_ICONS__)}catch{console.warn("[FrontFriend] Failed to parse __FF_ICONS__")}}else _&&window.__FF_ICONS__&&(n=window.__FF_ICONS__);return n&&e in n?n[e]:null},has(t,e){return!1},ownKeys(t){return[]},getOwnPropertyDescriptor(t,e){}});var I=y;export{S as componentsConfigSchema,m as config,I as default,h as ffdc,w as iconSet,O as isCSSClassString};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../index.mjs"],
4
- "sourcesContent": ["// ES Module wrapper for frontfriend-tailwind\n// This file provides ES module exports for both Node.js and browser environments\n\nimport { createRequire } from 'module';\n\nconst require = createRequire(import.meta.url);\nconst { componentsConfigSchema, isCSSClassString } = require('./lib/core/components-config-schema.js');\n\n// Determine environment\nconst isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';\nconst isNode = typeof process !== 'undefined' && process.versions && process.versions.node;\n\n// Lazy-loaded CJS module reference\nlet cjsModule = null;\n\n// Create plugin function that loads CJS module on demand\n// Uses synchronous require() which is safe because:\n// 1. Only runs in Node.js (build-time, not browser)\n// 2. Node.js is single-threaded - no race conditions\n// 3. Tailwind config evaluation happens synchronously during build\nconst plugin = isNode\n ? function(...args) {\n if (!cjsModule) {\n try {\n // Use dynamic require - only available in Node.js\n const module = require('module');\n const req = module.createRequire(import.meta.url);\n cjsModule = req('./index.js');\n } catch (error) {\n console.error('[FrontFriend] Failed to load plugin:', error);\n return {};\n }\n }\n return typeof cjsModule === 'function' ? cjsModule(...args) : cjsModule;\n }\n : function() {\n // Browser: Use stub function\n if (isBrowser) {\n console.warn('[FrontFriend] The Tailwind plugin cannot be used directly in browser environments');\n }\n return {};\n };\n\n/**\n * Creates a deep proxy that gracefully handles arbitrary nested property access\n * without throwing errors. This is essential for SSR and build-time scenarios\n * where configuration might not be loaded yet.\n *\n * Features:\n * - Infinite depth access: config.a.b.c.d.e never crashes\n * - Referential equality: config.a === config.a (memoized)\n * - Iteration support: Object.keys(), spread operator, for...in\n * - Type coercion: Works with toString, valueOf, Symbol.toPrimitive\n * - 'in' operator: 'property' in config returns true\n *\n * @returns {Proxy} A proxy object that handles any property access safely\n *\n * @example\n * const config = createDeepProxy();\n * const value = config.sidebar.root.wrapper.base; // Never crashes\n * config.a === config.a; // true (referential equality)\n * 'anything' in config; // true\n * Object.keys(config); // []\n */\nfunction createDeepProxy() {\n // Cache for memoization - ensures referential equality\n // This is critical for React dependency arrays and equality checks\n const cache = new Map();\n\n const handler = {\n /**\n * Handles property access with memoization\n * Ensures config.a === config.a for referential equality\n */\n get(target, prop) {\n // Handle special cases for type coercion and inspection\n if (prop === Symbol.toPrimitive || prop === 'valueOf') {\n return () => '';\n }\n if (prop === 'toString' || prop === Symbol.toStringTag) {\n return () => '';\n }\n if (prop === 'constructor') {\n return Object;\n }\n\n // Return cached proxy for same property to maintain referential equality\n // This prevents issues with React hooks and memoization\n if (!cache.has(prop)) {\n cache.set(prop, createDeepProxy());\n }\n return cache.get(prop);\n },\n\n /**\n * Handles 'in' operator\n * Makes 'property' in config return true for any property\n */\n has(target, prop) {\n // Return true for all properties except internal symbols\n if (typeof prop === 'symbol' && prop.toString().includes('nodejs.util.inspect')) {\n return false;\n }\n return true;\n },\n\n /**\n * Handles Object.keys(), Object.getOwnPropertyNames(), for...in\n * Returns empty array since proxy represents missing/unknown config\n */\n ownKeys(target) {\n return [];\n },\n\n /**\n * Handles Object.getOwnPropertyDescriptor()\n * Required for proper iteration support with ownKeys\n */\n getOwnPropertyDescriptor(target, prop) {\n return {\n enumerable: true,\n configurable: true,\n };\n },\n };\n\n return new Proxy({}, handler);\n}\n\n/**\n * FrontFriend Design Config (ffdc) - Safe config wrapper with SSR support\n *\n * Wraps configuration objects to prevent crashes during SSR or when config\n * is not yet loaded. Returns actual config if valid, or a deep proxy fallback.\n *\n * This is the recommended way to access config in components to ensure\n * they work during both build-time (SSR) and runtime.\n *\n * @param {Object|null|undefined} config - The configuration object to wrap\n * @returns {Object|Proxy} The config object or a safe deep proxy\n *\n * @example\n * import { config, ffdc } from '@frontfriend/tailwind';\n *\n * // Safe access during SSR - never crashes\n * const sidebarConfig = ffdc(config || {}).sidebar;\n * const className = sidebarConfig.root.wrapper.base; // Always safe\n *\n * @example\n * // In a React component\n * function Sidebar() {\n * const cfg = ffdc(config).sidebar;\n * return <div className={cfg.root.base}>...</div>;\n * }\n */\nexport function ffdc(config) {\n // During SSR or initial load, config might not be available yet\n // Return a deep proxy that handles any property access without crashing\n if (!config || typeof config !== 'object') {\n return createDeepProxy();\n }\n\n return config;\n}\n\n// Export config and iconSet with lazy getters\n// In Node.js, load CJS module on first access\n// In browser, use proxies with global variable fallbacks\nexport const config = new Proxy({}, {\n // Cache for the loaded CJS module config\n _cjsConfig: null,\n // Cache for memoized deep proxies\n _proxyCache: new Map(),\n\n get(target, prop) {\n // Handle special cases for console.log, JSON.stringify, etc.\n if (prop === Symbol.toPrimitive || prop === 'valueOf') {\n return () => '';\n }\n if (prop === 'toString' || prop === Symbol.toStringTag) {\n return () => '[object Object]';\n }\n if (prop === 'constructor') {\n return Object;\n }\n\n // In Node.js, try to get config from CJS module first\n if (isNode && !this._cjsConfig && cjsModule) {\n this._cjsConfig = cjsModule.config;\n }\n\n if (isNode && this._cjsConfig && prop in this._cjsConfig) {\n return this._cjsConfig[prop];\n }\n\n // Try to get config from globals\n let _config = null;\n if (typeof __FF_CONFIG__ !== 'undefined') {\n _config = __FF_CONFIG__;\n } else if (typeof process !== 'undefined' && process.env) {\n if (process.env.NEXT_PUBLIC_FF_CONFIG) {\n try {\n _config = JSON.parse(process.env.NEXT_PUBLIC_FF_CONFIG);\n } catch (e) {\n console.warn('[FrontFriend] Failed to parse NEXT_PUBLIC_FF_CONFIG');\n }\n } else if (process.env.__FF_CONFIG__) {\n try {\n _config = JSON.parse(process.env.__FF_CONFIG__);\n } catch (e) {\n console.warn('[FrontFriend] Failed to parse __FF_CONFIG__');\n }\n }\n } else if (isBrowser && window.__FF_CONFIG__) {\n _config = window.__FF_CONFIG__;\n }\n\n // Return actual config value if it exists\n if (_config && prop in _config) {\n return _config[prop];\n }\n\n // Return memoized deep proxy for missing properties\n if (!this._proxyCache.has(prop)) {\n this._proxyCache.set(prop, createDeepProxy());\n }\n return this._proxyCache.get(prop);\n },\n\n has(target, prop) {\n return true;\n },\n\n ownKeys(target) {\n return [];\n },\n\n getOwnPropertyDescriptor(target, prop) {\n return {\n enumerable: true,\n configurable: true,\n };\n },\n });\n\nexport const iconSet = new Proxy({}, {\n // Cache for the loaded CJS module iconSet\n _cjsIconSet: null,\n\n get(target, prop) {\n if (prop === Symbol.toPrimitive || prop === 'valueOf') {\n return () => '';\n }\n if (prop === 'toString' || prop === Symbol.toStringTag) {\n return () => '[object Object]';\n }\n if (prop === 'constructor') {\n return Object;\n }\n\n // In Node.js, try to get iconSet from CJS module first\n if (isNode && !this._cjsIconSet && cjsModule) {\n this._cjsIconSet = cjsModule.iconSet;\n }\n\n if (isNode && this._cjsIconSet && prop in this._cjsIconSet) {\n return this._cjsIconSet[prop];\n }\n\n // Try to get icons from globals\n let _iconSet = null;\n if (typeof __FF_ICONS__ !== 'undefined') {\n _iconSet = __FF_ICONS__;\n } else if (typeof process !== 'undefined' && process.env) {\n if (process.env.NEXT_PUBLIC_FF_ICONS) {\n try {\n _iconSet = JSON.parse(process.env.NEXT_PUBLIC_FF_ICONS);\n } catch (e) {\n console.warn('[FrontFriend] Failed to parse NEXT_PUBLIC_FF_ICONS');\n }\n } else if (process.env.__FF_ICONS__) {\n try {\n _iconSet = JSON.parse(process.env.__FF_ICONS__);\n } catch (e) {\n console.warn('[FrontFriend] Failed to parse __FF_ICONS__');\n }\n }\n } else if (isBrowser && window.__FF_ICONS__) {\n _iconSet = window.__FF_ICONS__;\n }\n\n if (_iconSet && prop in _iconSet) {\n return _iconSet[prop];\n }\n\n return null;\n },\n\n has(target, prop) {\n return false;\n },\n\n ownKeys(target) {\n return [];\n },\n\n getOwnPropertyDescriptor(target, prop) {\n return undefined;\n },\n });\n\nexport { componentsConfigSchema, isCSSClassString };\n\n// Default export is the plugin\nexport default plugin;\n"],
5
- "mappings": "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",
6
- "names": ["createRequire", "require", "componentsConfigSchema", "isCSSClassString", "isBrowser", "isNode", "cjsModule", "plugin", "args", "error", "createDeepProxy", "cache", "handler", "target", "prop", "ffdc", "config", "_config", "iconSet", "_iconSet", "frontfriend_tailwind_default", "plugin"]
4
+ "sourcesContent": ["// ES Module wrapper for frontfriend-tailwind\n// This file provides ES module exports for both Node.js and browser environments\n\nimport { createRequire } from 'module';\n\nconst require = createRequire(import.meta.url);\nconst { componentsConfigSchema, isCSSClassString } = require('./lib/core/components-config-schema.js');\n\n// Determine environment\nconst isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';\nconst isNode = typeof process !== 'undefined' && process.versions && process.versions.node;\n\n// Lazy-loaded CJS module reference\nlet cjsModule = null;\n\n// Create plugin function that loads CJS module on demand\n// Uses synchronous require() which is safe because:\n// 1. Only runs in Node.js (build-time, not browser)\n// 2. Node.js is single-threaded - no race conditions\n// 3. Tailwind config evaluation happens synchronously during build\nconst plugin = isNode\n ? function(...args) {\n if (!cjsModule) {\n try {\n // Use dynamic require - only available in Node.js\n const module = require('module');\n const req = module.createRequire(import.meta.url);\n cjsModule = req('./index.js');\n } catch (error) {\n console.error('[FrontFriend] Failed to load plugin:', error);\n return {};\n }\n }\n return typeof cjsModule === 'function' ? cjsModule(...args) : cjsModule;\n }\n : function() {\n // Browser: Use stub function\n if (isBrowser) {\n console.warn('[FrontFriend] The Tailwind plugin cannot be used directly in browser environments');\n }\n return {};\n };\n\n/**\n * Creates a deep proxy that gracefully handles arbitrary nested property access\n * without throwing errors. This is essential for SSR and build-time scenarios\n * where configuration might not be loaded yet.\n *\n * Features:\n * - Infinite depth access: config.a.b.c.d.e never crashes\n * - Referential equality: config.a === config.a (memoized)\n * - Iteration support: Object.keys(), spread operator, for...in\n * - Type coercion: Works with toString, valueOf, Symbol.toPrimitive\n * - 'in' operator: 'property' in config returns true\n *\n * @returns {Proxy} A proxy object that handles any property access safely\n *\n * @example\n * const config = createDeepProxy();\n * const value = config.sidebar.root.wrapper.base; // Never crashes\n * config.a === config.a; // true (referential equality)\n * 'anything' in config; // true\n * Object.keys(config); // []\n */\nfunction createDeepProxy() {\n // Cache for memoization - ensures referential equality\n // This is critical for React dependency arrays and equality checks\n const cache = new Map();\n\n const handler = {\n /**\n * Handles property access with memoization\n * Ensures config.a === config.a for referential equality\n */\n get(target, prop) {\n // Handle special cases for type coercion and inspection\n if (prop === Symbol.toPrimitive || prop === 'valueOf') {\n return () => '';\n }\n if (prop === 'toString' || prop === Symbol.toStringTag) {\n return () => '';\n }\n if (prop === 'constructor') {\n return Object;\n }\n\n // Return cached proxy for same property to maintain referential equality\n // This prevents issues with React hooks and memoization\n if (!cache.has(prop)) {\n cache.set(prop, createDeepProxy());\n }\n return cache.get(prop);\n },\n\n /**\n * Handles 'in' operator\n * Makes 'property' in config return true for any property\n */\n has(target, prop) {\n // Return true for all properties except internal symbols\n if (typeof prop === 'symbol' && prop.toString().includes('nodejs.util.inspect')) {\n return false;\n }\n return true;\n },\n\n /**\n * Handles Object.keys(), Object.getOwnPropertyNames(), for...in\n * Returns empty array since proxy represents missing/unknown config\n */\n ownKeys(target) {\n return [];\n },\n\n /**\n * Handles Object.getOwnPropertyDescriptor()\n * Required for proper iteration support with ownKeys\n */\n getOwnPropertyDescriptor(target, prop) {\n return {\n enumerable: true,\n configurable: true,\n };\n },\n };\n\n return new Proxy({}, handler);\n}\n\nfunction isPlainObject(value) {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction mergeConfigTrees(left, right) {\n if (!isPlainObject(left) || !isPlainObject(right)) {\n return right === undefined ? left : right;\n }\n const result = { ...left };\n for (const [key, value] of Object.entries(right)) {\n result[key] = key in result ? mergeConfigTrees(result[key], value) : value;\n }\n return result;\n}\n\nfunction findTreeConflicts(left, right, path = [], conflicts = []) {\n if (left === undefined || right === undefined) return conflicts;\n if (!isPlainObject(left) || !isPlainObject(right)) {\n conflicts.push(path.join('.'));\n return conflicts;\n }\n for (const key of Object.keys(left)) {\n if (key in right) findTreeConflicts(left[key], right[key], [...path, key], conflicts);\n }\n return conflicts;\n}\n\nfunction normalizeV4Component(envelope, path = []) {\n if (!isPlainObject(envelope) || !('styles' in envelope || 'behavior' in envelope)) {\n return envelope;\n }\n const conflicts = findTreeConflicts(envelope.styles, envelope.behavior, path);\n if (conflicts.length > 0) {\n throw new Error(`Component config styles/behavior conflict at ${conflicts.join(', ')}`);\n }\n return mergeConfigTrees(envelope.styles || {}, envelope.behavior || {});\n}\n\nfunction normalizeV4Config(config) {\n let changed = false;\n const result = {};\n for (const [name, envelope] of Object.entries(config)) {\n result[name] = normalizeV4Component(envelope, [name]);\n if (result[name] !== envelope) changed = true;\n }\n return changed ? result : config;\n}\n\n/**\n * FrontFriend Design Config (ffdc) - Safe config wrapper with SSR support\n *\n * Wraps configuration objects to prevent crashes during SSR or when config\n * is not yet loaded. Returns actual config if valid, or a deep proxy fallback.\n *\n * This is the recommended way to access config in components to ensure\n * they work during both build-time (SSR) and runtime.\n *\n * @param {Object|null|undefined} config - The configuration object to wrap\n * @returns {Object|Proxy} The config object or a safe deep proxy\n *\n * @example\n * import { config, ffdc } from '@frontfriend/tailwind';\n *\n * // Safe access during SSR - never crashes\n * const sidebarConfig = ffdc(config || {}).sidebar;\n * const className = sidebarConfig.root.wrapper.base; // Always safe\n *\n * @example\n * // In a React component\n * function Sidebar() {\n * const cfg = ffdc(config).sidebar;\n * return <div className={cfg.root.base}>...</div>;\n * }\n */\nexport function ffdc(config) {\n // During SSR or initial load, config might not be available yet\n // Return a deep proxy that handles any property access without crashing\n if (!config || typeof config !== 'object') {\n return createDeepProxy();\n }\n\n return normalizeV4Config(config);\n}\n\n// Export config and iconSet with lazy getters\n// In Node.js, load CJS module on first access\n// In browser, use proxies with global variable fallbacks\nexport const config = new Proxy({}, {\n // Cache for the loaded CJS module config\n _cjsConfig: null,\n // Cache for memoized deep proxies\n _proxyCache: new Map(),\n\n get(target, prop) {\n // Handle special cases for console.log, JSON.stringify, etc.\n if (prop === Symbol.toPrimitive || prop === 'valueOf') {\n return () => '';\n }\n if (prop === 'toString' || prop === Symbol.toStringTag) {\n return () => '[object Object]';\n }\n if (prop === 'constructor') {\n return Object;\n }\n\n // In Node.js, try to get config from CJS module first\n if (isNode && !this._cjsConfig && cjsModule) {\n this._cjsConfig = cjsModule.config;\n }\n\n if (isNode && this._cjsConfig && prop in this._cjsConfig) {\n return this._cjsConfig[prop];\n }\n\n // Try to get config from globals\n let _config = null;\n if (typeof __FF_CONFIG__ !== 'undefined') {\n _config = __FF_CONFIG__;\n } else if (typeof process !== 'undefined' && process.env) {\n if (process.env.NEXT_PUBLIC_FF_CONFIG) {\n try {\n _config = JSON.parse(process.env.NEXT_PUBLIC_FF_CONFIG);\n } catch (e) {\n console.warn('[FrontFriend] Failed to parse NEXT_PUBLIC_FF_CONFIG');\n }\n } else if (process.env.__FF_CONFIG__) {\n try {\n _config = JSON.parse(process.env.__FF_CONFIG__);\n } catch (e) {\n console.warn('[FrontFriend] Failed to parse __FF_CONFIG__');\n }\n }\n } else if (isBrowser && window.__FF_CONFIG__) {\n _config = window.__FF_CONFIG__;\n }\n\n // Return actual config value if it exists\n if (_config && prop in _config) {\n return normalizeV4Component(_config[prop], [String(prop)]);\n }\n\n // Return memoized deep proxy for missing properties\n if (!this._proxyCache.has(prop)) {\n this._proxyCache.set(prop, createDeepProxy());\n }\n return this._proxyCache.get(prop);\n },\n\n has(target, prop) {\n return true;\n },\n\n ownKeys(target) {\n return [];\n },\n\n getOwnPropertyDescriptor(target, prop) {\n return {\n enumerable: true,\n configurable: true,\n };\n },\n });\n\nexport const iconSet = new Proxy({}, {\n // Cache for the loaded CJS module iconSet\n _cjsIconSet: null,\n\n get(target, prop) {\n if (prop === Symbol.toPrimitive || prop === 'valueOf') {\n return () => '';\n }\n if (prop === 'toString' || prop === Symbol.toStringTag) {\n return () => '[object Object]';\n }\n if (prop === 'constructor') {\n return Object;\n }\n\n // In Node.js, try to get iconSet from CJS module first\n if (isNode && !this._cjsIconSet && cjsModule) {\n this._cjsIconSet = cjsModule.iconSet;\n }\n\n if (isNode && this._cjsIconSet && prop in this._cjsIconSet) {\n return this._cjsIconSet[prop];\n }\n\n // Try to get icons from globals\n let _iconSet = null;\n if (typeof __FF_ICONS__ !== 'undefined') {\n _iconSet = __FF_ICONS__;\n } else if (typeof process !== 'undefined' && process.env) {\n if (process.env.NEXT_PUBLIC_FF_ICONS) {\n try {\n _iconSet = JSON.parse(process.env.NEXT_PUBLIC_FF_ICONS);\n } catch (e) {\n console.warn('[FrontFriend] Failed to parse NEXT_PUBLIC_FF_ICONS');\n }\n } else if (process.env.__FF_ICONS__) {\n try {\n _iconSet = JSON.parse(process.env.__FF_ICONS__);\n } catch (e) {\n console.warn('[FrontFriend] Failed to parse __FF_ICONS__');\n }\n }\n } else if (isBrowser && window.__FF_ICONS__) {\n _iconSet = window.__FF_ICONS__;\n }\n\n if (_iconSet && prop in _iconSet) {\n return _iconSet[prop];\n }\n\n return null;\n },\n\n has(target, prop) {\n return false;\n },\n\n ownKeys(target) {\n return [];\n },\n\n getOwnPropertyDescriptor(target, prop) {\n return undefined;\n },\n });\n\nexport { componentsConfigSchema, isCSSClassString };\n\n// Default export is the plugin\nexport default plugin;\n"],
5
+ "mappings": "AAGA,OAAS,iBAAAA,MAAqB,SAE9B,IAAMC,EAAUD,EAAc,YAAY,GAAG,EACvC,CAAE,uBAAAE,EAAwB,iBAAAC,CAAiB,EAAIF,EAAQ,wCAAwC,EAG/FG,EAAY,OAAO,OAAW,KAAe,OAAO,OAAO,SAAa,IACxEC,EAAS,OAAO,QAAY,KAAe,QAAQ,UAAY,QAAQ,SAAS,KAGlFC,EAAY,KAOVC,EAASF,EACX,YAAYG,EAAM,CAChB,GAAI,CAACF,EACH,GAAI,CAIFA,EAFeL,EAAQ,QAAQ,EACZ,cAAc,YAAY,GAAG,EAChC,YAAY,CAC9B,OAASQ,EAAO,CACd,eAAQ,MAAM,uCAAwCA,CAAK,EACpD,CAAC,CACV,CAEF,OAAO,OAAOH,GAAc,WAAaA,EAAU,GAAGE,CAAI,EAAIF,CAChE,EACA,UAAW,CAET,OAAIF,GACF,QAAQ,KAAK,mFAAmF,EAE3F,CAAC,CACV,EAuBJ,SAASM,GAAkB,CAGzB,IAAMC,EAAQ,IAAI,IAEZC,EAAU,CAKd,IAAIC,EAAQC,EAAM,CAEhB,OAAIA,IAAS,OAAO,aAAeA,IAAS,UACnC,IAAM,GAEXA,IAAS,YAAcA,IAAS,OAAO,YAClC,IAAM,GAEXA,IAAS,cACJ,QAKJH,EAAM,IAAIG,CAAI,GACjBH,EAAM,IAAIG,EAAMJ,EAAgB,CAAC,EAE5BC,EAAM,IAAIG,CAAI,EACvB,EAMA,IAAID,EAAQC,EAAM,CAEhB,MAAI,SAAOA,GAAS,UAAYA,EAAK,SAAS,EAAE,SAAS,qBAAqB,EAIhF,EAMA,QAAQD,EAAQ,CACd,MAAO,CAAC,CACV,EAMA,yBAAyBA,EAAQC,EAAM,CACrC,MAAO,CACL,WAAY,GACZ,aAAc,EAChB,CACF,CACF,EAEA,OAAO,IAAI,MAAM,CAAC,EAAGF,CAAO,CAC9B,CAEA,SAASG,EAAcC,EAAO,CAC5B,OAAOA,IAAU,MAAQ,OAAOA,GAAU,UAAY,CAAC,MAAM,QAAQA,CAAK,CAC5E,CAEA,SAASC,EAAiBC,EAAMC,EAAO,CACrC,GAAI,CAACJ,EAAcG,CAAI,GAAK,CAACH,EAAcI,CAAK,EAC9C,OAAOA,IAAU,OAAYD,EAAOC,EAEtC,IAAMC,EAAS,CAAE,GAAGF,CAAK,EACzB,OAAW,CAACG,EAAKL,CAAK,IAAK,OAAO,QAAQG,CAAK,EAC7CC,EAAOC,CAAG,EAAIA,KAAOD,EAASH,EAAiBG,EAAOC,CAAG,EAAGL,CAAK,EAAIA,EAEvE,OAAOI,CACT,CAEA,SAASE,EAAkBJ,EAAMC,EAAOI,EAAO,CAAC,EAAGC,EAAY,CAAC,EAAG,CACjE,GAAIN,IAAS,QAAaC,IAAU,OAAW,OAAOK,EACtD,GAAI,CAACT,EAAcG,CAAI,GAAK,CAACH,EAAcI,CAAK,EAC9C,OAAAK,EAAU,KAAKD,EAAK,KAAK,GAAG,CAAC,EACtBC,EAET,QAAWH,KAAO,OAAO,KAAKH,CAAI,EAC5BG,KAAOF,GAAOG,EAAkBJ,EAAKG,CAAG,EAAGF,EAAME,CAAG,EAAG,CAAC,GAAGE,EAAMF,CAAG,EAAGG,CAAS,EAEtF,OAAOA,CACT,CAEA,SAASC,EAAqBC,EAAUH,EAAO,CAAC,EAAG,CACjD,GAAI,CAACR,EAAcW,CAAQ,GAAK,EAAE,WAAYA,GAAY,aAAcA,GACtE,OAAOA,EAET,IAAMF,EAAYF,EAAkBI,EAAS,OAAQA,EAAS,SAAUH,CAAI,EAC5E,GAAIC,EAAU,OAAS,EACrB,MAAM,IAAI,MAAM,gDAAgDA,EAAU,KAAK,IAAI,CAAC,EAAE,EAExF,OAAOP,EAAiBS,EAAS,QAAU,CAAC,EAAGA,EAAS,UAAY,CAAC,CAAC,CACxE,CAEA,SAASC,EAAkBC,EAAQ,CACjC,IAAIC,EAAU,GACRT,EAAS,CAAC,EAChB,OAAW,CAACU,EAAMJ,CAAQ,IAAK,OAAO,QAAQE,CAAM,EAClDR,EAAOU,CAAI,EAAIL,EAAqBC,EAAU,CAACI,CAAI,CAAC,EAChDV,EAAOU,CAAI,IAAMJ,IAAUG,EAAU,IAE3C,OAAOA,EAAUT,EAASQ,CAC5B,CA4BO,SAASG,EAAKH,EAAQ,CAG3B,MAAI,CAACA,GAAU,OAAOA,GAAW,SACxBlB,EAAgB,EAGlBiB,EAAkBC,CAAM,CACjC,CAKO,IAAMA,EAAS,IAAI,MAAM,CAAC,EAAG,CAE9B,WAAY,KAEZ,YAAa,IAAI,IAEjB,IAAIf,EAAQC,EAAM,CAEhB,GAAIA,IAAS,OAAO,aAAeA,IAAS,UAC1C,MAAO,IAAM,GAEf,GAAIA,IAAS,YAAcA,IAAS,OAAO,YACzC,MAAO,IAAM,kBAEf,GAAIA,IAAS,cACX,OAAO,OAQT,GAJIT,GAAU,CAAC,KAAK,YAAcC,IAChC,KAAK,WAAaA,EAAU,QAG1BD,GAAU,KAAK,YAAcS,KAAQ,KAAK,WAC5C,OAAO,KAAK,WAAWA,CAAI,EAI7B,IAAIkB,EAAU,KACd,GAAI,OAAO,cAAkB,IAC3BA,EAAU,sBACD,OAAO,QAAY,KAAe,QAAQ,KACnD,GAAI,QAAQ,IAAI,sBACd,GAAI,CACFA,EAAU,KAAK,MAAM,QAAQ,IAAI,qBAAqB,CACxD,MAAY,CACV,QAAQ,KAAK,qDAAqD,CACpE,SACS,QAAQ,IAAI,cACrB,GAAI,CACFA,EAAU,KAAK,MAAM,QAAQ,IAAI,aAAa,CAChD,MAAY,CACV,QAAQ,KAAK,6CAA6C,CAC5D,OAEO5B,GAAa,OAAO,gBAC7B4B,EAAU,OAAO,eAInB,OAAIA,GAAWlB,KAAQkB,EACdP,EAAqBO,EAAQlB,CAAI,EAAG,CAAC,OAAOA,CAAI,CAAC,CAAC,GAItD,KAAK,YAAY,IAAIA,CAAI,GAC5B,KAAK,YAAY,IAAIA,EAAMJ,EAAgB,CAAC,EAEvC,KAAK,YAAY,IAAII,CAAI,EAClC,EAEA,IAAID,EAAQC,EAAM,CAChB,MAAO,EACT,EAEA,QAAQD,EAAQ,CACd,MAAO,CAAC,CACV,EAEA,yBAAyBA,EAAQC,EAAM,CACrC,MAAO,CACL,WAAY,GACZ,aAAc,EAChB,CACF,CACF,CAAC,EAEQmB,EAAU,IAAI,MAAM,CAAC,EAAG,CAE/B,YAAa,KAEb,IAAIpB,EAAQC,EAAM,CAChB,GAAIA,IAAS,OAAO,aAAeA,IAAS,UAC1C,MAAO,IAAM,GAEf,GAAIA,IAAS,YAAcA,IAAS,OAAO,YACzC,MAAO,IAAM,kBAEf,GAAIA,IAAS,cACX,OAAO,OAQT,GAJIT,GAAU,CAAC,KAAK,aAAeC,IACjC,KAAK,YAAcA,EAAU,SAG3BD,GAAU,KAAK,aAAeS,KAAQ,KAAK,YAC7C,OAAO,KAAK,YAAYA,CAAI,EAI9B,IAAIoB,EAAW,KACf,GAAI,OAAO,aAAiB,IAC1BA,EAAW,qBACF,OAAO,QAAY,KAAe,QAAQ,KACnD,GAAI,QAAQ,IAAI,qBACd,GAAI,CACFA,EAAW,KAAK,MAAM,QAAQ,IAAI,oBAAoB,CACxD,MAAY,CACV,QAAQ,KAAK,oDAAoD,CACnE,SACS,QAAQ,IAAI,aACrB,GAAI,CACFA,EAAW,KAAK,MAAM,QAAQ,IAAI,YAAY,CAChD,MAAY,CACV,QAAQ,KAAK,4CAA4C,CAC3D,OAEO9B,GAAa,OAAO,eAC7B8B,EAAW,OAAO,cAGpB,OAAIA,GAAYpB,KAAQoB,EACfA,EAASpB,CAAI,EAGf,IACT,EAEA,IAAID,EAAQC,EAAM,CAChB,MAAO,EACT,EAEA,QAAQD,EAAQ,CACd,MAAO,CAAC,CACV,EAEA,yBAAyBA,EAAQC,EAAM,CAEvC,CACF,CAAC,EAKL,IAAOqB,EAAQC",
6
+ "names": ["createRequire", "require", "componentsConfigSchema", "isCSSClassString", "isBrowser", "isNode", "cjsModule", "plugin", "args", "error", "createDeepProxy", "cache", "handler", "target", "prop", "isPlainObject", "value", "mergeConfigTrees", "left", "right", "result", "key", "findTreeConflicts", "path", "conflicts", "normalizeV4Component", "envelope", "normalizeV4Config", "config", "changed", "name", "ffdc", "_config", "iconSet", "_iconSet", "frontfriend_tailwind_default", "plugin"]
7
7
  }
@@ -1,3 +1,3 @@
1
- var j=(s,e)=>()=>(e||s((e={exports:{}}).exports,e),e.exports);var R=j((Ie,q)=>{var le="https://app.dev.frontfriend.dev",he="https://registry-legacy.frontfriend.dev",ue=".cache/frontfriend",fe={JS:["tokens.js","variables.js","semanticVariables.js","semanticDarkVariables.js","safelist.js","custom.js"],JSON:["fonts.json","icons.json","components-config.json","version.json","metadata.json"]},de={FF_ID:"FF_ID",FF_API_URL:"FF_API_URL",FF_USE_LOCAL:"FF_USE_LOCAL",FF_AUTH_TOKEN:"FF_AUTH_TOKEN"};q.exports={DEFAULT_API_URL:le,LEGACY_API_URL:he,CACHE_DIR_NAME:ue,CACHE_TTL_DAYS:7,CACHE_TTL_MS:6048e5,CACHE_FILES:fe,ENV_VARS:de}});var H=j((Ne,M)=>{var $=class extends Error{constructor(e,t,o){super(e),this.name="APIError",this.statusCode=t,this.url=o,this.code=`API_${t}`}},A=class extends Error{constructor(e,t){super(e),this.name="CacheError",this.operation=t,this.code=`CACHE_${t.toUpperCase()}`}},P=class extends Error{constructor(e,t){super(e),this.name="ConfigError",this.field=t,this.code=t?`CONFIG_${String(t).toUpperCase()}`:"CONFIG_ERROR"}},S=class extends Error{constructor(e,t){super(e),this.name="ProcessingError",this.token=t,this.code="PROCESSING_ERROR"}};M.exports={APIError:$,CacheError:A,ConfigError:P,ProcessingError:S}});var U=j((xe,G)=>{var y=require("fs");function pe(s){try{let e=y.readFileSync(s,"utf8");return JSON.parse(e)}catch(e){if(e.code==="ENOENT")return null;throw e}}function me(s){try{return y.readFileSync(s,"utf8").replace(/^\uFEFF/,"")}catch(e){if(e.code==="ENOENT")return null;throw e}}function ye(s,e,t=2){let o=JSON.stringify(e,null,t);y.writeFileSync(s,o,"utf8")}function ge(s,e){y.writeFileSync(s,e,"utf8")}function we(s,e){if(e==null||typeof e=="object"&&Object.keys(e).length===0||Array.isArray(e)&&e.length===0){let o=`module.exports = ${Array.isArray(e)?"[]":"{}"};`;y.writeFileSync(s,o,"utf8")}else{let t=`module.exports = ${JSON.stringify(e,null,2)};`;y.writeFileSync(s,t,"utf8")}}function Ce(s){return y.existsSync(s)}function ke(s){y.mkdirSync(s,{recursive:!0})}function Fe(s){y.rmSync(s,{recursive:!0,force:!0})}G.exports={readJsonFileSafe:pe,readFileSafe:me,writeJsonFile:ye,writeTextFile:ge,writeModuleExportsFile:we,fileExists:Ce,ensureDirectoryExists:ke,removeDirectory:Fe}});var V=j((Je,B)=>{var g=require("path"),{fileExists:D}=U();function je(s,e=process.cwd()){let t=e;for(;t!==g.parse(t).root;){let o=g.join(t,s);if(D(o))return o;t=g.dirname(t)}return null}function Te(s,e=process.cwd(),t=null){let o=[],n=e,a=10;for(let r=0;r<a;r++){o.push(g.join(n,s)),r<3&&o.push(g.join(n,"../".repeat(r+1)+s));let i=g.dirname(n);if(i===n)break;n=i}o.push(g.join(__dirname,"../../../",s));for(let r of o)if(D(r)&&(!t||t(r)))return r;return null}function Ee(s,e=process.cwd()){let t=s.map(o=>g.isAbsolute(o)?o:g.join(e,o));for(let o of t)if(D(o))return o;return null}B.exports={findFileUpward:je,findDirectoryUpward:Te,findDirectoryWithPaths:Ee}});var K=j((Oe,z)=>{var h=require("path"),{findDirectoryUpward:W}=V(),{readJsonFileSafe:w,readFileSafe:Y,fileExists:v}=U(),L=class{constructor(e,t={}){if(this.ffId=e,this.tokensBasePath=t.tokensBasePath||this.findTokensPath(),this.folderMap=this.loadFolderMap(),this.projectFolder=this.folderMap[e],!this.projectFolder)throw new Error(`No folder mapping found for ff-id: ${e}`);this.projectPath=h.join(this.tokensBasePath,this.projectFolder)}findTokensPath(){let e=W("apps/tokens",process.cwd(),t=>v(h.join(t,"folderMap.json")));if(e||(e=W("tokens",process.cwd(),t=>v(h.join(t,"folderMap.json")))),!e)throw new Error("Could not find tokens directory with folderMap.json");return e}loadFolderMap(){let e=h.join(this.tokensBasePath,"folderMap.json"),t=w(e);if(!t)throw new Error("Failed to load folderMap.json: File not found");return t}async fetchTokens(){let e=h.join(this.projectPath,"figma"),t={global:[h.join(e,"Global Tokens","Default.json"),h.join(e,"global.json")],colors:[h.join(e,"Global Colors","Default.json"),h.join(e,"Global Colors","Light.json")],semantic:[h.join(e,"Semantic","Light.json"),h.join(e,"Semantic","Default.json")],semanticDark:[h.join(e,"Semantic","Dark.json")]},o={};for(let[n,a]of Object.entries(t)){for(let r of a){let i=w(r);if(i!==null){o[n]=i;break}}o[n]||(o[n]=null)}return o}async fetchProcessedTokens(){let e=h.join(this.projectPath,"cache");if(!v(e))return null;let t=r=>{if(r===null)return null;let i={},u={exports:i};return new Function("module","exports",r)(u,i),u.exports},o={tokens:{fileName:"hashedTokens.js",type:"module"},variables:{fileName:"hashedVariables.js",type:"module"},semanticVariables:{fileName:"hashedSemanticVariables.js",type:"module"},semanticDarkVariables:{fileName:"hashedSemanticDarkVariables.js",type:"module"},safelist:{fileName:"safelist.js",type:"module"},custom:{fileName:"custom.js",type:"module"},fonts:{fileName:"fonts.json",type:"json"},icons:{fileName:"icons.json",type:"json"},componentsConfig:{fileName:"encoded-config.json",type:"json"},version:{fileName:"version.json",type:"json"}},n={};for(let[r,{fileName:i,type:u}]of Object.entries(o)){let c=h.join(e,i),d=u==="module"?t(Y(c)):w(c);d!==null&&(n[r]=d)}return Object.values(n).some(r=>r!==null)?n:null}async fetchComponentsConfig(){return w(h.join(this.projectPath,"components-config.json"))}async fetchFonts(){return w(h.join(this.projectPath,"font.json"))}async fetchIcons(){return w(h.join(this.projectPath,"icons.json"))}async fetchVersion(){return w(h.join(this.projectPath,"version.json"))}async fetchCustomCss(){return Y(h.join(this.projectPath,"custom.css"))}async fetchPlanMetadata(){return w(h.join(this.projectPath,"metadata.json"))||{planType:"full",allowedComponents:null}}fetchJson(){throw new Error("fetchJson is not implemented in LocalTokenReader. Use specific fetch methods.")}fetchRaw(){throw new Error("fetchRaw is not implemented in LocalTokenReader. Use specific fetch methods.")}};z.exports={LocalTokenReader:L}});var ae=j((qe,re)=>{var C=require("fs"),Q=require("path"),_e=require("os"),Re=require("https"),$e=require("http"),{URL:Ae}=require("url"),{DEFAULT_API_URL:X}=R(),Z=Q.join(_e.homedir(),".frontfriend"),k=Q.join(Z,"credentials");function Pe(){return k}function ee(){try{return C.existsSync(k)?JSON.parse(C.readFileSync(k,"utf8")):null}catch{return null}}function te(s){C.mkdirSync(Z,{recursive:!0,mode:448}),C.writeFileSync(k,`${JSON.stringify(s,null,2)}
2
- `,{mode:384});try{C.chmodSync(k,384)}catch{}}function Se(){return C.existsSync(k)?(C.unlinkSync(k),!0):!1}function ne(s,e=60*1e3){return!(s!=null&&s.accessToken)||!s.expiresAt||Date.now()+e>=s.expiresAt}function E(s){let e=new Error(`${s}. Run \`frontfriend login\` to re-authenticate.`);return e.code="FF_AUTH_REFRESH_FAILED",e}function se(s,e,t){return new Promise((o,n)=>{let a=new Ae(s),r=a.protocol==="https:"?Re:$e,i=JSON.stringify(e||{}),u=r.request({hostname:a.hostname,port:a.port,path:`${a.pathname}${a.search}`,method:"POST",headers:{"content-type":"application/json","content-length":Buffer.byteLength(i),...t?{authorization:`Bearer ${t}`}:{}}},c=>{let d="";c.on("data",l=>{d+=l}),c.on("end",()=>{if(c.statusCode>=300&&c.statusCode<400){let p=c.headers.location?` to ${c.headers.location}`:"",m=new Error(`HTTP ${c.statusCode}: redirected${p}`);m.statusCode=c.statusCode,m.body=d,n(m);return}let l=null;try{l=d?JSON.parse(d):null}catch{let m=c.headers["content-type"]||"unknown content-type",T=new Error(`Expected JSON from FrontFriend API at ${s}, but received ${m} (HTTP ${c.statusCode}). Check FF_API_URL or pass --api-url with the FrontFriend app URL.`);if(T.statusCode=c.statusCode,T.body=d,c.statusCode>=400){n(T);return}n(T);return}if(c.statusCode>=400){let p=new Error((l==null?void 0:l.error_description)||(l==null?void 0:l.error)||`HTTP ${c.statusCode}`);p.statusCode=c.statusCode,p.body=l,n(p);return}o(l)})});u.on("error",n),u.write(i),u.end()})}async function oe(s,e=X){if(!(s!=null&&s.refreshToken)||!(s!=null&&s.deviceId))throw E("FrontFriend session expired");let t;try{t=await se(`${e}/api/plugin/token`,{grant_type:"refresh_token",refresh_token:s.refreshToken,device_id:s.deviceId})}catch(n){throw E((n==null?void 0:n.message)||"Could not refresh FrontFriend session")}if(!(t!=null&&t.access_token)||!(t!=null&&t.refresh_token))throw E("Could not refresh FrontFriend session");let o={accessToken:t.access_token,refreshToken:t.refresh_token,deviceId:t.device_id||s.deviceId,expiresAt:Date.now()+(t.expires_in||900)*1e3,refreshExpiresAt:Date.now()+(t.refresh_expires_in||604800)*1e3,ffApiUrl:e};return te(o),o}async function Ue(s={}){if(!s.skipCredentials){let e=ee();if(e!=null&&e.accessToken||e!=null&&e.refreshToken){let t=s.baseURL||e.ffApiUrl||X;return e.accessToken&&!ne(e)?e.accessToken:(await oe(e,t)).accessToken}}return s.envToken?s.envToken:s.legacyToken?(s.silent||console.warn("\u26A0\uFE0F auth-token in frontfriend.config.js is deprecated. Run `frontfriend login` to store credentials outside the repo."),s.legacyToken):null}re.exports={getCredentialsPath:Pe,readCredentials:ee,writeCredentials:te,deleteCredentials:Se,isExpired:ne,postJson:se,refreshCredentials:oe,resolveAuthToken:Ue,createAuthRefreshError:E}});var b=require("https"),I=require("http"),{URL:x}=require("url"),{DEFAULT_API_URL:De,LEGACY_API_URL:F,ENV_VARS:N}=R(),{APIError:f}=H(),{LocalTokenReader:ve}=K(),{resolveAuthToken:Le}=ae(),_="Authentication required. Run `frontfriend login` to re-authenticate.";function ie(s,e,t,o){return t?s.get(new x(e),{headers:{authorization:`Bearer ${t}`}},o):s.get(e,o)}function J(s,e=""){var o;let t=((o=s.headers)==null?void 0:o.location)||"";return s.statusCode===401||s.statusCode===403||s.statusCode>=300&&s.statusCode<400&&t.includes("/sign-in")||String(e).trim().startsWith("/sign-in")}function ce(s,e,t=""){if(J(s,t))return new f(_,s.statusCode,e);let o=s.statusMessage;try{let n=t?JSON.parse(t):null;n!=null&&n.error&&(o=n.error);let a=[...Array.isArray(n==null?void 0:n.cssErrors)?n.cssErrors.slice(0,5).map(r=>`${r.property}: ${r.className}`):[],...Array.isArray(n==null?void 0:n.schemaErrors)?n.schemaErrors.slice(0,5):[]];a.length>0&&(o=`${o} (${a.join("; ")})`)}catch{}return new f(`HTTP ${s.statusCode}: ${o}`,s.statusCode,e)}var O=class{constructor(e,t={}){this.ffId=e,this.baseURL=t.baseURL||process.env[N.FF_API_URL]||De,this.legacyAuthToken=t.authToken||null,this.authToken=null,this.skipCredentials=t.skipCredentials||!1,process.env[N.FF_USE_LOCAL]==="true"&&(console.log(" \u{1F3E0} Using local token reader"),this.localReader=new ve(e,t))}async getAuthToken(){return this.authToken=await Le({baseURL:this.baseURL,envToken:process.env[N.FF_AUTH_TOKEN],legacyToken:this.legacyAuthToken,skipCredentials:this.skipCredentials}),this.authToken}async fetchJson(e,t={}){let o=await this.getAuthToken();return new Promise((n,a)=>{let r=e.startsWith("https")?b:I;ie(r,e,o,i=>{let u="";if(i.statusCode>=300){a(ce(i,e));return}i.on("data",c=>{u+=c}),i.on("end",()=>{try{let c=JSON.parse(u);t.returnHeaders?n({data:c,headers:i.headers}):n(c)}catch(c){if(J(i,u)){a(new f(_,i.statusCode,e));return}a(new f(`Invalid JSON response: ${c.message}`,i.statusCode,e))}}),i.on("error",c=>{a(new f(`Response error: ${c.message}`,i.statusCode,e))})}).on("error",i=>{a(new f(`Network error: ${i.message}`,0,e))})})}async fetchRaw(e){let t=await this.getAuthToken();return new Promise((o,n)=>{let a=e.startsWith("https")?b:I;ie(a,e,t,r=>{let i="";if(r.statusCode>=400){n(new f(`HTTP ${r.statusCode}: ${r.statusMessage}`,r.statusCode,e));return}r.on("data",u=>{i+=u}),r.on("end",()=>{o(i)}),r.on("error",u=>{n(new f(`Response error: ${u.message}`,r.statusCode,e))})}).on("error",r=>{n(new f(`Network error: ${r.message}`,0,e))})})}async fetchTokens(){if(this.localReader)return this.localReader.fetchTokens();try{let n=`${this.baseURL}/api/design-systems/${this.ffId}/tokens`,a=await this.fetchJson(n);if(a&&a.tokens){let r=a.tokens;return{global:r["Global Tokens/Default"]||r.global||null,colors:r["Global Colors/Default"]||r.colors||null,semantic:r["Semantic/Light"]||r["semantic/light"]||null,semanticDark:r["Semantic/Dark"]||r["semantic/dark"]||null}}}catch(n){if(n.statusCode===400)throw new f("Design system not synced with Figma. Please sync tokens from Figma before using this design system.",400,`${this.baseURL}/api/design-systems/${this.ffId}/tokens`)}let e=F,t={global:`${e}/${this.ffId}/global-tokens/default.json`,colors:`${e}/${this.ffId}/global-colors/default.json`,semantic:`${e}/${this.ffId}/semantic/light.json`,semanticDark:`${e}/${this.ffId}/semantic/dark.json`},o=await Promise.all([this.fetchJson(t.global).catch(n=>n.statusCode===404?null:Promise.reject(n)),this.fetchJson(t.colors).catch(n=>n.statusCode===404?null:Promise.reject(n)),this.fetchJson(t.semantic).catch(n=>n.statusCode===404?null:Promise.reject(n)),this.fetchJson(t.semanticDark).catch(n=>n.statusCode===404?null:Promise.reject(n))]);return{global:o[0],colors:o[1],semantic:o[2],semanticDark:o[3]}}async fetchProcessedTokens(e={}){if(this.localReader)return this.localReader.fetchProcessedTokens();let t=new x(`${this.baseURL}/api/design-systems/${this.ffId}/processed-tokens`);e.tag&&t.searchParams.append("tag",e.tag),e.version&&t.searchParams.append("version",e.version),e.tailwindV4&&t.searchParams.append("tailwind","v4");let o=t.toString();try{let n=await this.fetchJson(o,{returnHeaders:!0});return n.headers&&(n.data.versionMetadata={version:n.headers["x-frontfriend-version"],tag:n.headers["x-frontfriend-tag"],cached:n.headers["x-frontfriend-cached"]==="true"}),n.data}catch(n){if(n.statusCode===404)return null;throw n.statusCode===400?new f("Design system not synced with Figma. Please sync tokens from Figma before using this design system.",400,o):n}}async sendJson(e,t,o){let n=await this.getAuthToken();if(!n)throw new f(_,401,e);return new Promise((a,r)=>{let i=new x(e),u=e.startsWith("https")?b:I,c=JSON.stringify(o||{}),d=u.request({hostname:i.hostname,port:i.port,path:`${i.pathname}${i.search}`,method:t,headers:{"content-type":"application/json","content-length":Buffer.byteLength(c),...n?{authorization:`Bearer ${n}`}:{}}},l=>{let p="";l.on("data",m=>{p+=m}),l.on("end",()=>{if(l.statusCode>=300){r(ce(l,e,p));return}if(!p){a(null);return}try{a(JSON.parse(p))}catch(m){if(J(l,p)){r(new f(_,l.statusCode,e));return}r(new f(`Invalid JSON response: ${m.message}`,l.statusCode,e))}})});d.on("error",l=>{r(new f(`Network error: ${l.message}`,0,e))}),d.write(c),d.end()})}async pushComponentsConfig(e,t,o,n={}){let a=`${this.baseURL}/api/design-systems/${this.ffId}/components-config`,r={componentsConfig:e};return typeof t=="string"&&t.length>0&&(r.customCss=t),typeof o=="string"&&o.length>0&&(r.iconLibrary=o),n.themeStudioRecipe&&typeof n.themeStudioRecipe=="object"&&(r.themeStudioRecipe=n.themeStudioRecipe),this.sendJson(a,"PUT",r)}async fetchComponentsConfig(){if(this.localReader)return this.localReader.fetchComponentsConfig();let e=`${F}/${this.ffId}/components-config.json`;try{return await this.fetchJson(e)}catch(t){if(t.statusCode===404)return null;throw t}}async fetchFonts(){if(this.localReader)return this.localReader.fetchFonts();let e=`${F}/${this.ffId}/font.json`;try{return await this.fetchJson(e)}catch(t){if(t.statusCode===404)return null;throw t}}async fetchIcons(){if(this.localReader)return this.localReader.fetchIcons();let e=`${F}/${this.ffId}/icons.json`;try{return await this.fetchJson(e)}catch(t){if(t.statusCode===404)return null;throw t}}async fetchVersion(){if(this.localReader)return this.localReader.fetchVersion();let e=`${F}/${this.ffId}/version.json`;try{return await this.fetchJson(e)}catch(t){if(t.statusCode===404)return null;throw t}}async fetchCustomCss(){if(this.localReader)return this.localReader.fetchCustomCss();let e=`${F}/${this.ffId}/custom.css`;try{return await this.fetchRaw(e)}catch(t){if(t.statusCode===404)return null;throw t}}async fetchPlanMetadata(){if(this.localReader)return process.env.FF_DEBUG&&console.log(" \u2192 Using local reader for plan metadata"),this.localReader.fetchPlanMetadata();let e=`${this.baseURL}/api/design-systems/${this.ffId}/processed-tokens`;try{process.env.FF_DEBUG&&console.log(` \u2192 Fetching plan metadata from saas app: ${e}`);let t=await this.fetchJson(e);if(t&&t.metadata){let o={planType:t.metadata.planType||"full",allowedComponents:t.metadata.allowedComponents||null};return process.env.FF_DEBUG&&console.log(` \u2192 Found plan metadata in saas app: ${o.planType}, allowed: ${o.allowedComponents?o.allowedComponents.length+" components":"all"}`),o}}catch(t){if(t.statusCode===404){process.env.FF_DEBUG&&console.log(" \u2192 ff-id not found in saas app, trying legacy server");let o=`${F}/${this.ffId}/metadata`;try{process.env.FF_DEBUG&&console.log(` \u2192 Fetching from legacy server: ${o}`);let n=await this.fetchJson(o),a={planType:n.planType||"full",allowedComponents:n.allowedComponents||null};return process.env.FF_DEBUG&&console.log(` \u2192 Found in legacy server: ${a.planType}, allowed: ${a.allowedComponents?a.allowedComponents.length+" components":"all"}`),a}catch(n){if(n.statusCode===404)return process.env.FF_DEBUG&&console.log(" \u2192 ff-id not found in any server - access denied"),{planType:"denied",allowedComponents:[],error:"Design system not found. Please ensure your ff-id is valid."};throw n}}throw t}}};module.exports={APIClient:O};
1
+ var T=(n,e)=>()=>(e||n((e={exports:{}}).exports,e),e.exports);var $=T((Ie,M)=>{var le="https://app.dev.frontfriend.dev",he="https://registry-legacy.frontfriend.dev",ue=".cache/frontfriend",fe={JS:["tokens.js","variables.js","semanticVariables.js","semanticDarkVariables.js","safelist.js","custom.js"],JSON:["fonts.json","icons.json","components-config.json","version.json","metadata.json"]},de={FF_ID:"FF_ID",FF_API_URL:"FF_API_URL",FF_USE_LOCAL:"FF_USE_LOCAL",FF_AUTH_TOKEN:"FF_AUTH_TOKEN"};M.exports={DEFAULT_API_URL:le,LEGACY_API_URL:he,CACHE_DIR_NAME:ue,CACHE_TTL_DAYS:7,CACHE_TTL_MS:6048e5,CACHE_FILES:fe,ENV_VARS:de}});var H=T((Ne,q)=>{var R=class extends Error{constructor(e,t,o){super(e),this.name="APIError",this.statusCode=t,this.url=o,this.code=`API_${t}`}},S=class extends Error{constructor(e,t){super(e),this.name="CacheError",this.operation=t,this.code=`CACHE_${t.toUpperCase()}`}},P=class extends Error{constructor(e,t){super(e),this.name="ConfigError",this.field=t,this.code=t?`CONFIG_${String(t).toUpperCase()}`:"CONFIG_ERROR"}},A=class extends Error{constructor(e,t){super(e),this.name="ProcessingError",this.token=t,this.code="PROCESSING_ERROR"}};q.exports={APIError:R,CacheError:S,ConfigError:P,ProcessingError:A}});var U=T((xe,G)=>{var y=require("fs");function pe(n){try{let e=y.readFileSync(n,"utf8");return JSON.parse(e)}catch(e){if(e.code==="ENOENT")return null;throw e}}function me(n){try{return y.readFileSync(n,"utf8").replace(/^\uFEFF/,"")}catch(e){if(e.code==="ENOENT")return null;throw e}}function ye(n,e,t=2){let o=JSON.stringify(e,null,t);y.writeFileSync(n,o,"utf8")}function ge(n,e){y.writeFileSync(n,e,"utf8")}function we(n,e){if(e==null||typeof e=="object"&&Object.keys(e).length===0||Array.isArray(e)&&e.length===0){let o=`module.exports = ${Array.isArray(e)?"[]":"{}"};`;y.writeFileSync(n,o,"utf8")}else{let t=`module.exports = ${JSON.stringify(e,null,2)};`;y.writeFileSync(n,t,"utf8")}}function Ce(n){return y.existsSync(n)}function ke(n){y.mkdirSync(n,{recursive:!0})}function Fe(n){y.rmSync(n,{recursive:!0,force:!0})}G.exports={readJsonFileSafe:pe,readFileSafe:me,writeJsonFile:ye,writeTextFile:ge,writeModuleExportsFile:we,fileExists:Ce,ensureDirectoryExists:ke,removeDirectory:Fe}});var V=T((Je,B)=>{var g=require("path"),{fileExists:D}=U();function Te(n,e=process.cwd()){let t=e;for(;t!==g.parse(t).root;){let o=g.join(t,n);if(D(o))return o;t=g.dirname(t)}return null}function je(n,e=process.cwd(),t=null){let o=[],s=e,a=10;for(let r=0;r<a;r++){o.push(g.join(s,n)),r<3&&o.push(g.join(s,"../".repeat(r+1)+n));let i=g.dirname(s);if(i===s)break;s=i}o.push(g.join(__dirname,"../../../",n));for(let r of o)if(D(r)&&(!t||t(r)))return r;return null}function Ee(n,e=process.cwd()){let t=n.map(o=>g.isAbsolute(o)?o:g.join(e,o));for(let o of t)if(D(o))return o;return null}B.exports={findFileUpward:Te,findDirectoryUpward:je,findDirectoryWithPaths:Ee}});var K=T((Oe,z)=>{var h=require("path"),{findDirectoryUpward:W}=V(),{readJsonFileSafe:w,readFileSafe:Y,fileExists:v}=U(),L=class{constructor(e,t={}){if(this.ffId=e,this.tokensBasePath=t.tokensBasePath||this.findTokensPath(),this.folderMap=this.loadFolderMap(),this.projectFolder=this.folderMap[e],!this.projectFolder)throw new Error(`No folder mapping found for ff-id: ${e}`);this.projectPath=h.join(this.tokensBasePath,this.projectFolder)}findTokensPath(){let e=W("apps/tokens",process.cwd(),t=>v(h.join(t,"folderMap.json")));if(e||(e=W("tokens",process.cwd(),t=>v(h.join(t,"folderMap.json")))),!e)throw new Error("Could not find tokens directory with folderMap.json");return e}loadFolderMap(){let e=h.join(this.tokensBasePath,"folderMap.json"),t=w(e);if(!t)throw new Error("Failed to load folderMap.json: File not found");return t}async fetchTokens(){let e=h.join(this.projectPath,"figma"),t={global:[h.join(e,"Global Tokens","Default.json"),h.join(e,"global.json")],colors:[h.join(e,"Global Colors","Default.json"),h.join(e,"Global Colors","Light.json")],semantic:[h.join(e,"Semantic","Light.json"),h.join(e,"Semantic","Default.json")],semanticDark:[h.join(e,"Semantic","Dark.json")]},o={};for(let[s,a]of Object.entries(t)){for(let r of a){let i=w(r);if(i!==null){o[s]=i;break}}o[s]||(o[s]=null)}return o}async fetchProcessedTokens(){let e=h.join(this.projectPath,"cache");if(!v(e))return null;let t=r=>{if(r===null)return null;let i={},u={exports:i};return new Function("module","exports",r)(u,i),u.exports},o={tokens:{fileName:"hashedTokens.js",type:"module"},variables:{fileName:"hashedVariables.js",type:"module"},semanticVariables:{fileName:"hashedSemanticVariables.js",type:"module"},semanticDarkVariables:{fileName:"hashedSemanticDarkVariables.js",type:"module"},safelist:{fileName:"safelist.js",type:"module"},custom:{fileName:"custom.js",type:"module"},fonts:{fileName:"fonts.json",type:"json"},icons:{fileName:"icons.json",type:"json"},componentsConfig:{fileName:"encoded-config.json",type:"json"},version:{fileName:"version.json",type:"json"}},s={};for(let[r,{fileName:i,type:u}]of Object.entries(o)){let c=h.join(e,i),d=u==="module"?t(Y(c)):w(c);d!==null&&(s[r]=d)}return Object.values(s).some(r=>r!==null)?s:null}async fetchComponentsConfig(){return w(h.join(this.projectPath,"components-config.json"))}async fetchFonts(){return w(h.join(this.projectPath,"font.json"))}async fetchIcons(){return w(h.join(this.projectPath,"icons.json"))}async fetchVersion(){return w(h.join(this.projectPath,"version.json"))}async fetchCustomCss(){return Y(h.join(this.projectPath,"custom.css"))}async fetchPlanMetadata(){return w(h.join(this.projectPath,"metadata.json"))||{planType:"full",allowedComponents:null}}fetchJson(){throw new Error("fetchJson is not implemented in LocalTokenReader. Use specific fetch methods.")}fetchRaw(){throw new Error("fetchRaw is not implemented in LocalTokenReader. Use specific fetch methods.")}};z.exports={LocalTokenReader:L}});var ae=T((Me,re)=>{var C=require("fs"),Q=require("path"),_e=require("os"),$e=require("https"),Re=require("http"),{URL:Se}=require("url"),{DEFAULT_API_URL:X}=$(),Z=Q.join(_e.homedir(),".frontfriend"),k=Q.join(Z,"credentials");function Pe(){return k}function ee(){try{return C.existsSync(k)?JSON.parse(C.readFileSync(k,"utf8")):null}catch{return null}}function te(n){C.mkdirSync(Z,{recursive:!0,mode:448}),C.writeFileSync(k,`${JSON.stringify(n,null,2)}
2
+ `,{mode:384});try{C.chmodSync(k,384)}catch{}}function Ae(){return C.existsSync(k)?(C.unlinkSync(k),!0):!1}function se(n,e=60*1e3){return!(n!=null&&n.accessToken)||!n.expiresAt||Date.now()+e>=n.expiresAt}function E(n){let e=new Error(`${n}. Run \`frontfriend login\` to re-authenticate.`);return e.code="FF_AUTH_REFRESH_FAILED",e}function ne(n,e,t){return new Promise((o,s)=>{let a=new Se(n),r=a.protocol==="https:"?$e:Re,i=JSON.stringify(e||{}),u=r.request({hostname:a.hostname,port:a.port,path:`${a.pathname}${a.search}`,method:"POST",headers:{"content-type":"application/json","content-length":Buffer.byteLength(i),...t?{authorization:`Bearer ${t}`}:{}}},c=>{let d="";c.on("data",l=>{d+=l}),c.on("end",()=>{if(c.statusCode>=300&&c.statusCode<400){let p=c.headers.location?` to ${c.headers.location}`:"",m=new Error(`HTTP ${c.statusCode}: redirected${p}`);m.statusCode=c.statusCode,m.body=d,s(m);return}let l=null;try{l=d?JSON.parse(d):null}catch{let m=c.headers["content-type"]||"unknown content-type",j=new Error(`Expected JSON from FrontFriend API at ${n}, but received ${m} (HTTP ${c.statusCode}). Check FF_API_URL or pass --api-url with the FrontFriend app URL.`);if(j.statusCode=c.statusCode,j.body=d,c.statusCode>=400){s(j);return}s(j);return}if(c.statusCode>=400){let p=new Error((l==null?void 0:l.error_description)||(l==null?void 0:l.error)||`HTTP ${c.statusCode}`);p.statusCode=c.statusCode,p.body=l,s(p);return}o(l)})});u.on("error",s),u.write(i),u.end()})}async function oe(n,e=X){if(!(n!=null&&n.refreshToken)||!(n!=null&&n.deviceId))throw E("FrontFriend session expired");let t;try{t=await ne(`${e}/api/plugin/token`,{grant_type:"refresh_token",refresh_token:n.refreshToken,device_id:n.deviceId})}catch(s){throw E((s==null?void 0:s.message)||"Could not refresh FrontFriend session")}if(!(t!=null&&t.access_token)||!(t!=null&&t.refresh_token))throw E("Could not refresh FrontFriend session");let o={accessToken:t.access_token,refreshToken:t.refresh_token,deviceId:t.device_id||n.deviceId,expiresAt:Date.now()+(t.expires_in||900)*1e3,refreshExpiresAt:Date.now()+(t.refresh_expires_in||604800)*1e3,ffApiUrl:e};return te(o),o}async function Ue(n={}){if(!n.skipCredentials){let e=ee();if(e!=null&&e.accessToken||e!=null&&e.refreshToken){let t=n.baseURL||e.ffApiUrl||X;return e.accessToken&&!se(e)?e.accessToken:(await oe(e,t)).accessToken}}return n.envToken?n.envToken:n.legacyToken?(n.silent||console.warn("\u26A0\uFE0F auth-token in frontfriend.config.js is deprecated. Run `frontfriend login` to store credentials outside the repo."),n.legacyToken):null}re.exports={getCredentialsPath:Pe,readCredentials:ee,writeCredentials:te,deleteCredentials:Ae,isExpired:se,postJson:ne,refreshCredentials:oe,resolveAuthToken:Ue,createAuthRefreshError:E}});var b=require("https"),I=require("http"),{URL:x}=require("url"),{DEFAULT_API_URL:De,LEGACY_API_URL:F,ENV_VARS:N}=$(),{APIError:f}=H(),{LocalTokenReader:ve}=K(),{resolveAuthToken:Le}=ae(),_="Authentication required. Run `frontfriend login` to re-authenticate.";function ie(n,e,t,o){return t?n.get(new x(e),{headers:{authorization:`Bearer ${t}`}},o):n.get(e,o)}function J(n,e=""){var o;let t=((o=n.headers)==null?void 0:o.location)||"";return n.statusCode===401||n.statusCode===403||n.statusCode>=300&&n.statusCode<400&&t.includes("/sign-in")||String(e).trim().startsWith("/sign-in")}function ce(n,e,t=""){if(J(n,t))return new f(_,n.statusCode,e);let o=n.statusMessage;try{let s=t?JSON.parse(t):null;s!=null&&s.error&&(o=s.error);let a=[...Array.isArray(s==null?void 0:s.cssErrors)?s.cssErrors.slice(0,5).map(r=>`${r.property}: ${r.className}`):[],...Array.isArray(s==null?void 0:s.schemaErrors)?s.schemaErrors.slice(0,5):[]];a.length>0&&(o=`${o} (${a.join("; ")})`)}catch{}return new f(`HTTP ${n.statusCode}: ${o}`,n.statusCode,e)}var O=class{constructor(e,t={}){this.ffId=e,this.baseURL=t.baseURL||process.env[N.FF_API_URL]||De,this.legacyAuthToken=t.authToken||null,this.authToken=null,this.skipCredentials=t.skipCredentials||!1,process.env[N.FF_USE_LOCAL]==="true"&&(console.log(" \u{1F3E0} Using local token reader"),this.localReader=new ve(e,t))}async getAuthToken(){return this.authToken=await Le({baseURL:this.baseURL,envToken:process.env[N.FF_AUTH_TOKEN],legacyToken:this.legacyAuthToken,skipCredentials:this.skipCredentials}),this.authToken}async fetchJson(e,t={}){let o=await this.getAuthToken();return new Promise((s,a)=>{let r=e.startsWith("https")?b:I;ie(r,e,o,i=>{let u="";if(i.statusCode>=300){a(ce(i,e));return}i.on("data",c=>{u+=c}),i.on("end",()=>{try{let c=JSON.parse(u);t.returnHeaders?s({data:c,headers:i.headers}):s(c)}catch(c){if(J(i,u)){a(new f(_,i.statusCode,e));return}a(new f(`Invalid JSON response: ${c.message}`,i.statusCode,e))}}),i.on("error",c=>{a(new f(`Response error: ${c.message}`,i.statusCode,e))})}).on("error",i=>{a(new f(`Network error: ${i.message}`,0,e))})})}async fetchRaw(e){let t=await this.getAuthToken();return new Promise((o,s)=>{let a=e.startsWith("https")?b:I;ie(a,e,t,r=>{let i="";if(r.statusCode>=400){s(new f(`HTTP ${r.statusCode}: ${r.statusMessage}`,r.statusCode,e));return}r.on("data",u=>{i+=u}),r.on("end",()=>{o(i)}),r.on("error",u=>{s(new f(`Response error: ${u.message}`,r.statusCode,e))})}).on("error",r=>{s(new f(`Network error: ${r.message}`,0,e))})})}async fetchTokens(){if(this.localReader)return this.localReader.fetchTokens();try{let s=`${this.baseURL}/api/design-systems/${this.ffId}/tokens`,a=await this.fetchJson(s);if(a&&a.tokens){let r=a.tokens;return{global:r["Global Tokens/Default"]||r.global||null,colors:r["Global Colors/Default"]||r.colors||null,semantic:r["Semantic/Light"]||r["semantic/light"]||null,semanticDark:r["Semantic/Dark"]||r["semantic/dark"]||null}}}catch(s){if(s.statusCode===400)throw new f("Design system not synced with Figma. Please sync tokens from Figma before using this design system.",400,`${this.baseURL}/api/design-systems/${this.ffId}/tokens`)}let e=F,t={global:`${e}/${this.ffId}/global-tokens/default.json`,colors:`${e}/${this.ffId}/global-colors/default.json`,semantic:`${e}/${this.ffId}/semantic/light.json`,semanticDark:`${e}/${this.ffId}/semantic/dark.json`},o=await Promise.all([this.fetchJson(t.global).catch(s=>s.statusCode===404?null:Promise.reject(s)),this.fetchJson(t.colors).catch(s=>s.statusCode===404?null:Promise.reject(s)),this.fetchJson(t.semantic).catch(s=>s.statusCode===404?null:Promise.reject(s)),this.fetchJson(t.semanticDark).catch(s=>s.statusCode===404?null:Promise.reject(s))]);return{global:o[0],colors:o[1],semantic:o[2],semanticDark:o[3]}}async fetchProcessedTokens(e={}){if(this.localReader)return this.localReader.fetchProcessedTokens();let t=new x(`${this.baseURL}/api/design-systems/${this.ffId}/processed-tokens`);e.tag&&t.searchParams.append("tag",e.tag),e.version&&t.searchParams.append("version",e.version),e.tailwindV4&&t.searchParams.append("tailwind","v4");let o=t.toString();try{let s=await this.fetchJson(o,{returnHeaders:!0});return s.headers&&(s.data.versionMetadata={version:s.headers["x-frontfriend-version"],tag:s.headers["x-frontfriend-tag"],cached:s.headers["x-frontfriend-cached"]==="true"}),s.data}catch(s){if(s.statusCode===404)return null;throw s.statusCode===400?new f("Design system not synced with Figma. Please sync tokens from Figma before using this design system.",400,o):s}}async sendJson(e,t,o){let s=await this.getAuthToken();if(!s)throw new f(_,401,e);return new Promise((a,r)=>{let i=new x(e),u=e.startsWith("https")?b:I,c=JSON.stringify(o||{}),d=u.request({hostname:i.hostname,port:i.port,path:`${i.pathname}${i.search}`,method:t,headers:{"content-type":"application/json","content-length":Buffer.byteLength(c),...s?{authorization:`Bearer ${s}`}:{}}},l=>{let p="";l.on("data",m=>{p+=m}),l.on("end",()=>{if(l.statusCode>=300){r(ce(l,e,p));return}if(!p){a(null);return}try{a(JSON.parse(p))}catch(m){if(J(l,p)){r(new f(_,l.statusCode,e));return}r(new f(`Invalid JSON response: ${m.message}`,l.statusCode,e))}})});d.on("error",l=>{r(new f(`Network error: ${l.message}`,0,e))}),d.write(c),d.end()})}async pushComponentsConfig(e,t,o,s={}){let a=`${this.baseURL}/api/design-systems/${this.ffId}/components-config`,r={componentsConfig:e};return typeof t=="string"&&t.length>0&&(r.customCss=t),typeof o=="string"&&o.length>0&&(r.iconLibrary=o),s.themeStudioRecipe&&typeof s.themeStudioRecipe=="object"&&(r.themeStudioRecipe=s.themeStudioRecipe),this.sendJson(a,"PUT",r)}async migrateComponents(e){let t=`${this.baseURL}/api/design-systems/${this.ffId}/migrate`;return this.sendJson(t,"POST",e)}async listMigrationSnapshots(){let e=`${this.baseURL}/api/design-systems/${this.ffId}/migrate/snapshots`;return this.fetchJson(e)}async getMigrationSnapshot(e){let t=`${this.baseURL}/api/design-systems/${this.ffId}/migrate/snapshots/${e}`;return this.fetchJson(t)}async fetchComponentsConfig(){if(this.localReader)return this.localReader.fetchComponentsConfig();let e=`${F}/${this.ffId}/components-config.json`;try{return await this.fetchJson(e)}catch(t){if(t.statusCode===404)return null;throw t}}async fetchFonts(){if(this.localReader)return this.localReader.fetchFonts();let e=`${F}/${this.ffId}/font.json`;try{return await this.fetchJson(e)}catch(t){if(t.statusCode===404)return null;throw t}}async fetchIcons(){if(this.localReader)return this.localReader.fetchIcons();let e=`${F}/${this.ffId}/icons.json`;try{return await this.fetchJson(e)}catch(t){if(t.statusCode===404)return null;throw t}}async fetchVersion(){if(this.localReader)return this.localReader.fetchVersion();let e=`${F}/${this.ffId}/version.json`;try{return await this.fetchJson(e)}catch(t){if(t.statusCode===404)return null;throw t}}async fetchCustomCss(){if(this.localReader)return this.localReader.fetchCustomCss();let e=`${F}/${this.ffId}/custom.css`;try{return await this.fetchRaw(e)}catch(t){if(t.statusCode===404)return null;throw t}}async fetchPlanMetadata(){if(this.localReader)return process.env.FF_DEBUG&&console.log(" \u2192 Using local reader for plan metadata"),this.localReader.fetchPlanMetadata();let e=`${this.baseURL}/api/design-systems/${this.ffId}/processed-tokens`;try{process.env.FF_DEBUG&&console.log(` \u2192 Fetching plan metadata from saas app: ${e}`);let t=await this.fetchJson(e);if(t&&t.metadata){let o={planType:t.metadata.planType||"full",allowedComponents:t.metadata.allowedComponents||null};return process.env.FF_DEBUG&&console.log(` \u2192 Found plan metadata in saas app: ${o.planType}, allowed: ${o.allowedComponents?o.allowedComponents.length+" components":"all"}`),o}}catch(t){if(t.statusCode===404){process.env.FF_DEBUG&&console.log(" \u2192 ff-id not found in saas app, trying legacy server");let o=`${F}/${this.ffId}/metadata`;try{process.env.FF_DEBUG&&console.log(` \u2192 Fetching from legacy server: ${o}`);let s=await this.fetchJson(o),a={planType:s.planType||"full",allowedComponents:s.allowedComponents||null};return process.env.FF_DEBUG&&console.log(` \u2192 Found in legacy server: ${a.planType}, allowed: ${a.allowedComponents?a.allowedComponents.length+" components":"all"}`),a}catch(s){if(s.statusCode===404)return process.env.FF_DEBUG&&console.log(" \u2192 ff-id not found in any server - access denied"),{planType:"denied",allowedComponents:[],error:"Design system not found. Please ensure your ff-id is valid."};throw s}}throw t}}};module.exports={APIClient:O};
3
3
  //# sourceMappingURL=api-client.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../lib/core/constants.js", "../../../lib/core/errors.js", "../../../lib/core/file-utils.js", "../../../lib/core/path-utils.js", "../../../lib/core/local-token-reader.js", "../../../lib/core/credentials.js", "../../../lib/core/api-client.js"],
4
- "sourcesContent": ["/**\n * Configuration constants for FrontFriend Tailwind v2\n */\n\n// API Configuration. The platform currently lives on the dev deployment \u2014\n// keep this as the CLI default so `frontfriend login`/init work zero-config.\nconst DEFAULT_API_URL = 'https://app.dev.frontfriend.dev';\nconst LEGACY_API_URL = 'https://registry-legacy.frontfriend.dev';\n\n// Cache Configuration\nconst CACHE_DIR_NAME = '.cache/frontfriend';\nconst CACHE_TTL_DAYS = 7;\nconst CACHE_TTL_MS = CACHE_TTL_DAYS * 24 * 60 * 60 * 1000;\n\n// File names\nconst CACHE_FILES = {\n JS: [\n 'tokens.js',\n 'variables.js',\n 'semanticVariables.js',\n 'semanticDarkVariables.js',\n 'safelist.js',\n 'custom.js'\n ],\n JSON: [\n 'fonts.json',\n 'icons.json',\n 'components-config.json',\n 'version.json',\n 'metadata.json'\n ]\n};\n\n// Environment variables\nconst ENV_VARS = {\n FF_ID: 'FF_ID',\n FF_API_URL: 'FF_API_URL',\n FF_USE_LOCAL: 'FF_USE_LOCAL',\n FF_AUTH_TOKEN: 'FF_AUTH_TOKEN'\n};\n\nmodule.exports = {\n DEFAULT_API_URL,\n LEGACY_API_URL,\n CACHE_DIR_NAME,\n CACHE_TTL_DAYS,\n CACHE_TTL_MS,\n CACHE_FILES,\n ENV_VARS\n};", "class APIError extends Error {\n constructor(message, statusCode, url) {\n super(message);\n this.name = 'APIError';\n this.statusCode = statusCode;\n this.url = url;\n this.code = `API_${statusCode}`;\n }\n}\n\nclass CacheError extends Error {\n constructor(message, operation) {\n super(message);\n this.name = 'CacheError';\n this.operation = operation;\n this.code = `CACHE_${operation.toUpperCase()}`;\n }\n}\n\nclass ConfigError extends Error {\n constructor(message, field) {\n super(message);\n this.name = 'ConfigError';\n this.field = field;\n // `field` is optional; guard so a missing field never crashes (and masks)\n // the real error with `Cannot read properties of undefined (toUpperCase)`.\n this.code = field ? `CONFIG_${String(field).toUpperCase()}` : 'CONFIG_ERROR';\n }\n}\n\nclass ProcessingError extends Error {\n constructor(message, token) {\n super(message);\n this.name = 'ProcessingError';\n this.token = token;\n this.code = 'PROCESSING_ERROR';\n }\n}\n\nmodule.exports = {\n APIError,\n CacheError,\n ConfigError,\n ProcessingError\n};", "const fs = require('fs');\n\n/**\n * Read a JSON file safely, returning null if file doesn't exist\n * @param {string} filepath - Path to the JSON file\n * @returns {Object|null} Parsed JSON or null if file not found\n * @throws {Error} If JSON is invalid\n */\nfunction readJsonFileSafe(filepath) {\n try {\n const content = fs.readFileSync(filepath, 'utf8');\n return JSON.parse(content);\n } catch (error) {\n if (error.code === 'ENOENT') {\n return null; // File not found, return null like API would return 404\n }\n throw error;\n }\n}\n\n/**\n * Read a file safely, returning null if file doesn't exist\n * Strips UTF-8 BOM if present (fixes Windows compatibility)\n * @param {string} filepath - Path to the file\n * @returns {string|null} File content or null if file not found\n * @throws {Error} For other file system errors\n */\nfunction readFileSafe(filepath) {\n try {\n const content = fs.readFileSync(filepath, 'utf8');\n // Strip UTF-8 BOM if present (Windows compatibility)\n return content.replace(/^\\uFEFF/, '');\n } catch (error) {\n if (error.code === 'ENOENT') {\n return null; // File not found\n }\n throw error;\n }\n}\n\n/**\n * Write JSON data to a file with proper formatting\n * @param {string} filepath - Path to write the file\n * @param {Object} data - Data to write\n * @param {number} indent - Indentation level (default: 2)\n */\nfunction writeJsonFile(filepath, data, indent = 2) {\n const content = JSON.stringify(data, null, indent);\n fs.writeFileSync(filepath, content, 'utf8');\n}\n\n/**\n * Write plain text content to a file\n * @param {string} filepath - Path to write the file\n * @param {string} content - Text content to write\n */\nfunction writeTextFile(filepath, content) {\n fs.writeFileSync(filepath, content, 'utf8');\n}\n\n/**\n * Write module.exports file with JSON data\n * @param {string} filepath - Path to write the file\n * @param {Object} data - Data to export\n */\nfunction writeModuleExportsFile(filepath, data) {\n // Handle empty data cases\n if (data === null || data === undefined || \n (typeof data === 'object' && Object.keys(data).length === 0) ||\n (Array.isArray(data) && data.length === 0)) {\n const emptyContent = Array.isArray(data) ? '[]' : '{}';\n const content = `module.exports = ${emptyContent};`;\n fs.writeFileSync(filepath, content, 'utf8');\n } else {\n const content = `module.exports = ${JSON.stringify(data, null, 2)};`;\n fs.writeFileSync(filepath, content, 'utf8');\n }\n}\n\n/**\n * Check if a file exists\n * @param {string} filepath - Path to check\n * @returns {boolean} True if file exists\n */\nfunction fileExists(filepath) {\n return fs.existsSync(filepath);\n}\n\n/**\n * Create directory recursively\n * @param {string} dirpath - Directory path to create\n */\nfunction ensureDirectoryExists(dirpath) {\n fs.mkdirSync(dirpath, { recursive: true });\n}\n\n/**\n * Remove directory recursively\n * @param {string} dirpath - Directory path to remove\n */\nfunction removeDirectory(dirpath) {\n fs.rmSync(dirpath, { recursive: true, force: true });\n}\n\nmodule.exports = {\n readJsonFileSafe,\n readFileSafe,\n writeJsonFile,\n writeTextFile,\n writeModuleExportsFile,\n fileExists,\n ensureDirectoryExists,\n removeDirectory\n};\n", "const path = require('path');\nconst { fileExists } = require('./file-utils');\n\n/**\n * Find a file by traversing up the directory tree\n * @param {string} filename - Name of the file to find\n * @param {string} startDir - Starting directory (defaults to cwd)\n * @returns {string|null} Full path to the file or null if not found\n */\nfunction findFileUpward(filename, startDir = process.cwd()) {\n let currentDir = startDir;\n \n while (currentDir !== path.parse(currentDir).root) {\n const filePath = path.join(currentDir, filename);\n \n if (fileExists(filePath)) {\n return filePath;\n }\n \n currentDir = path.dirname(currentDir);\n }\n \n return null;\n}\n\n/**\n * Find a directory by traversing up and checking multiple possible paths\n * @param {string} dirname - Name of the directory to find\n * @param {string} startDir - Starting directory (defaults to cwd)\n * @param {Function} validator - Optional function to validate the directory\n * @returns {string|null} Full path to the directory or null if not found\n */\nfunction findDirectoryUpward(dirname, startDir = process.cwd(), validator = null) {\n const possiblePaths = [];\n let currentDir = startDir;\n const maxLevels = 10; // Prevent infinite loop\n \n // Build list of possible paths\n for (let i = 0; i < maxLevels; i++) {\n // Direct path\n possiblePaths.push(path.join(currentDir, dirname));\n \n // Relative paths up to 3 levels\n if (i < 3) {\n possiblePaths.push(path.join(currentDir, '../'.repeat(i + 1) + dirname));\n }\n \n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) break; // Reached root\n currentDir = parentDir;\n }\n \n // Also check from module directory (for when running from node_modules)\n possiblePaths.push(path.join(__dirname, '../../../', dirname));\n \n // Find first existing directory that passes validation\n for (const dirPath of possiblePaths) {\n if (fileExists(dirPath)) {\n if (!validator || validator(dirPath)) {\n return dirPath;\n }\n }\n }\n \n return null;\n}\n\n/**\n * Find a directory with multiple possible relative paths\n * @param {string[]} possiblePaths - Array of possible paths to check\n * @param {string} startDir - Starting directory (defaults to cwd)\n * @returns {string|null} Full path to the directory or null if not found\n */\nfunction findDirectoryWithPaths(possiblePaths, startDir = process.cwd()) {\n // Build absolute paths from the start directory\n const absolutePaths = possiblePaths.map(p => {\n if (path.isAbsolute(p)) {\n return p;\n }\n return path.join(startDir, p);\n });\n \n // Find first existing path\n for (const dirPath of absolutePaths) {\n if (fileExists(dirPath)) {\n return dirPath;\n }\n }\n \n return null;\n}\n\nmodule.exports = {\n findFileUpward,\n findDirectoryUpward,\n findDirectoryWithPaths\n};", "const path = require('path');\nconst { findDirectoryUpward } = require('./path-utils');\nconst { readJsonFileSafe, readFileSafe, fileExists } = require('./file-utils');\n\n/**\n * LocalTokenReader - Reads tokens directly from the local file system\n * Mimics the APIClient interface but reads from apps/tokens directory\n */\nclass LocalTokenReader {\n constructor(ffId, options = {}) {\n this.ffId = ffId;\n this.tokensBasePath = options.tokensBasePath || this.findTokensPath();\n this.folderMap = this.loadFolderMap();\n this.projectFolder = this.folderMap[ffId];\n \n if (!this.projectFolder) {\n throw new Error(`No folder mapping found for ff-id: ${ffId}`);\n }\n \n this.projectPath = path.join(this.tokensBasePath, this.projectFolder);\n }\n\n /**\n * Find the tokens directory by looking for apps/tokens in parent directories\n */\n findTokensPath() {\n // Try to find apps/tokens first\n let tokensPath = findDirectoryUpward('apps/tokens', process.cwd(), (dir) => {\n return fileExists(path.join(dir, 'folderMap.json'));\n });\n \n // If not found, try just 'tokens'\n if (!tokensPath) {\n tokensPath = findDirectoryUpward('tokens', process.cwd(), (dir) => {\n return fileExists(path.join(dir, 'folderMap.json'));\n });\n }\n \n if (!tokensPath) {\n throw new Error('Could not find tokens directory with folderMap.json');\n }\n \n return tokensPath;\n }\n\n /**\n * Load the folder mapping from folderMap.json\n */\n loadFolderMap() {\n const folderMapPath = path.join(this.tokensBasePath, 'folderMap.json');\n const folderMap = readJsonFileSafe(folderMapPath);\n \n if (!folderMap) {\n throw new Error(`Failed to load folderMap.json: File not found`);\n }\n \n return folderMap;\n }\n\n /**\n * Fetch all token files (global, colors, semantic)\n * Mimics the APIClient.fetchTokens() method\n */\n async fetchTokens() {\n const figmaPath = path.join(this.projectPath, 'figma');\n \n // Try different possible paths for tokens\n const tokenPaths = {\n global: [\n path.join(figmaPath, 'Global Tokens', 'Default.json'),\n path.join(figmaPath, 'global.json')\n ],\n colors: [\n path.join(figmaPath, 'Global Colors', 'Default.json'),\n path.join(figmaPath, 'Global Colors', 'Light.json')\n ],\n semantic: [\n path.join(figmaPath, 'Semantic', 'Light.json'),\n path.join(figmaPath, 'Semantic', 'Default.json')\n ],\n semanticDark: [\n path.join(figmaPath, 'Semantic', 'Dark.json')\n ]\n };\n\n const results = {};\n \n // Try each possible path for each token type\n for (const [key, paths] of Object.entries(tokenPaths)) {\n for (const tokenPath of paths) {\n const content = readJsonFileSafe(tokenPath);\n if (content !== null) {\n results[key] = content;\n break; // Found it, no need to try other paths\n }\n }\n // If not found in any path, set to null\n if (!results[key]) {\n results[key] = null;\n }\n }\n\n return results;\n }\n\n /**\n * Fetch pre-processed tokens (if available in cache folder)\n */\n async fetchProcessedTokens() {\n const cachePath = path.join(this.projectPath, 'cache');\n \n if (!fileExists(cachePath)) {\n return null;\n }\n\n const parseModuleExports = (content) => {\n if (content === null) return null;\n\n const moduleExports = {};\n const fakeModule = { exports: moduleExports };\n const evalFunc = new Function('module', 'exports', content);\n evalFunc(fakeModule, moduleExports);\n return fakeModule.exports;\n };\n\n // Read all local cache files and normalize them to CacheManager.save() keys.\n const cacheFiles = {\n tokens: { fileName: 'hashedTokens.js', type: 'module' },\n variables: { fileName: 'hashedVariables.js', type: 'module' },\n semanticVariables: { fileName: 'hashedSemanticVariables.js', type: 'module' },\n semanticDarkVariables: { fileName: 'hashedSemanticDarkVariables.js', type: 'module' },\n safelist: { fileName: 'safelist.js', type: 'module' },\n custom: { fileName: 'custom.js', type: 'module' },\n fonts: { fileName: 'fonts.json', type: 'json' },\n icons: { fileName: 'icons.json', type: 'json' },\n componentsConfig: { fileName: 'encoded-config.json', type: 'json' },\n version: { fileName: 'version.json', type: 'json' }\n };\n\n const processedData = {};\n \n for (const [key, { fileName, type }] of Object.entries(cacheFiles)) {\n const filePath = path.join(cachePath, fileName);\n const value = type === 'module'\n ? parseModuleExports(readFileSafe(filePath))\n : readJsonFileSafe(filePath);\n\n if (value !== null) {\n processedData[key] = value;\n }\n }\n\n // Only return if we have at least some data\n const hasData = Object.values(processedData).some(val => val !== null);\n return hasData ? processedData : null;\n }\n\n /**\n * Fetch components configuration\n */\n async fetchComponentsConfig() {\n return readJsonFileSafe(path.join(this.projectPath, 'components-config.json'));\n }\n\n /**\n * Fetch fonts configuration\n */\n async fetchFonts() {\n return readJsonFileSafe(path.join(this.projectPath, 'font.json'));\n }\n\n /**\n * Fetch icons configuration\n */\n async fetchIcons() {\n return readJsonFileSafe(path.join(this.projectPath, 'icons.json'));\n }\n\n /**\n * Fetch version information\n */\n async fetchVersion() {\n return readJsonFileSafe(path.join(this.projectPath, 'version.json'));\n }\n\n /**\n * Fetch custom CSS\n */\n async fetchCustomCss() {\n return readFileSafe(path.join(this.projectPath, 'custom.css'));\n }\n\n /**\n * Fetch plan metadata\n */\n async fetchPlanMetadata() {\n const metadata = readJsonFileSafe(path.join(this.projectPath, 'metadata.json'));\n \n // Default to full plan if no metadata exists\n return metadata || {\n planType: 'full',\n allowedComponents: null\n };\n }\n\n // Compatibility methods to match APIClient interface\n fetchJson() {\n throw new Error('fetchJson is not implemented in LocalTokenReader. Use specific fetch methods.');\n }\n\n fetchRaw() {\n throw new Error('fetchRaw is not implemented in LocalTokenReader. Use specific fetch methods.');\n }\n}\n\nmodule.exports = { LocalTokenReader };\n", "const fs = require('fs');\nconst path = require('path');\nconst os = require('os');\nconst https = require('https');\nconst http = require('http');\nconst { URL } = require('url');\nconst { DEFAULT_API_URL } = require('./constants');\n\nconst CREDENTIALS_DIR = path.join(os.homedir(), '.frontfriend');\nconst CREDENTIALS_PATH = path.join(CREDENTIALS_DIR, 'credentials');\n\nfunction getCredentialsPath() {\n return CREDENTIALS_PATH;\n}\n\nfunction readCredentials() {\n try {\n if (!fs.existsSync(CREDENTIALS_PATH)) return null;\n return JSON.parse(fs.readFileSync(CREDENTIALS_PATH, 'utf8'));\n } catch {\n return null;\n }\n}\n\nfunction writeCredentials(credentials) {\n fs.mkdirSync(CREDENTIALS_DIR, { recursive: true, mode: 0o700 });\n fs.writeFileSync(CREDENTIALS_PATH, `${JSON.stringify(credentials, null, 2)}\\n`, { mode: 0o600 });\n try {\n fs.chmodSync(CREDENTIALS_PATH, 0o600);\n } catch {\n // Best effort on platforms that do not support chmod.\n }\n}\n\nfunction deleteCredentials() {\n if (fs.existsSync(CREDENTIALS_PATH)) {\n fs.unlinkSync(CREDENTIALS_PATH);\n return true;\n }\n return false;\n}\n\nfunction isExpired(credentials, skewMs = 60 * 1000) {\n return !credentials?.accessToken || !credentials.expiresAt || Date.now() + skewMs >= credentials.expiresAt;\n}\n\nfunction createAuthRefreshError(message) {\n const error = new Error(`${message}. Run \\`frontfriend login\\` to re-authenticate.`);\n error.code = 'FF_AUTH_REFRESH_FAILED';\n return error;\n}\n\nfunction postJson(url, body, authToken) {\n return new Promise((resolve, reject) => {\n const parsedUrl = new URL(url);\n const protocol = parsedUrl.protocol === 'https:' ? https : http;\n const payload = JSON.stringify(body || {});\n const request = protocol.request({\n hostname: parsedUrl.hostname,\n port: parsedUrl.port,\n path: `${parsedUrl.pathname}${parsedUrl.search}`,\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'content-length': Buffer.byteLength(payload),\n ...(authToken ? { authorization: `Bearer ${authToken}` } : {}),\n },\n }, response => {\n let data = '';\n response.on('data', chunk => { data += chunk; });\n response.on('end', () => {\n if (response.statusCode >= 300 && response.statusCode < 400) {\n const redirectUrl = response.headers.location ? ` to ${response.headers.location}` : '';\n const error = new Error(`HTTP ${response.statusCode}: redirected${redirectUrl}`);\n error.statusCode = response.statusCode;\n error.body = data;\n reject(error);\n return;\n }\n\n let parsed = null;\n try {\n parsed = data ? JSON.parse(data) : null;\n } catch (error) {\n const contentType = response.headers['content-type'] || 'unknown content-type';\n const apiError = new Error(\n `Expected JSON from FrontFriend API at ${url}, but received ${contentType} (HTTP ${response.statusCode}). ` +\n 'Check FF_API_URL or pass --api-url with the FrontFriend app URL.'\n );\n apiError.statusCode = response.statusCode;\n apiError.body = data;\n if (response.statusCode >= 400) {\n reject(apiError);\n return;\n }\n reject(apiError);\n return;\n }\n if (response.statusCode >= 400) {\n const error = new Error(parsed?.error_description || parsed?.error || `HTTP ${response.statusCode}`);\n error.statusCode = response.statusCode;\n error.body = parsed;\n reject(error);\n return;\n }\n resolve(parsed);\n });\n });\n request.on('error', reject);\n request.write(payload);\n request.end();\n });\n}\n\nasync function refreshCredentials(credentials, baseURL = DEFAULT_API_URL) {\n if (!credentials?.refreshToken || !credentials?.deviceId) {\n throw createAuthRefreshError('FrontFriend session expired');\n }\n\n let response;\n try {\n response = await postJson(`${baseURL}/api/plugin/token`, {\n grant_type: 'refresh_token',\n refresh_token: credentials.refreshToken,\n device_id: credentials.deviceId,\n });\n } catch (error) {\n throw createAuthRefreshError(error?.message || 'Could not refresh FrontFriend session');\n }\n\n if (!response?.access_token || !response?.refresh_token) {\n throw createAuthRefreshError('Could not refresh FrontFriend session');\n }\n\n const refreshed = {\n accessToken: response.access_token,\n refreshToken: response.refresh_token,\n deviceId: response.device_id || credentials.deviceId,\n expiresAt: Date.now() + (response.expires_in || 900) * 1000,\n refreshExpiresAt: Date.now() + (response.refresh_expires_in || 604800) * 1000,\n ffApiUrl: baseURL,\n };\n writeCredentials(refreshed);\n return refreshed;\n}\n\nasync function resolveAuthToken(options = {}) {\n if (!options.skipCredentials) {\n const credentials = readCredentials();\n if (credentials?.accessToken || credentials?.refreshToken) {\n const baseURL = options.baseURL || credentials.ffApiUrl || DEFAULT_API_URL;\n if (credentials.accessToken && !isExpired(credentials)) {\n return credentials.accessToken;\n }\n const refreshed = await refreshCredentials(credentials, baseURL);\n return refreshed.accessToken;\n }\n }\n\n if (options.envToken) return options.envToken;\n if (options.legacyToken) {\n if (!options.silent) {\n console.warn('\u26A0\uFE0F auth-token in frontfriend.config.js is deprecated. Run `frontfriend login` to store credentials outside the repo.');\n }\n return options.legacyToken;\n }\n return null;\n}\n\nmodule.exports = {\n getCredentialsPath,\n readCredentials,\n writeCredentials,\n deleteCredentials,\n isExpired,\n postJson,\n refreshCredentials,\n resolveAuthToken,\n createAuthRefreshError,\n};\n", "const https = require('https');\nconst http = require('http');\nconst { URL } = require('url');\nconst { DEFAULT_API_URL, LEGACY_API_URL, ENV_VARS } = require('./constants');\nconst { APIError } = require('./errors');\nconst { LocalTokenReader } = require('./local-token-reader');\nconst { resolveAuthToken } = require('./credentials');\n\nconst AUTH_REQUIRED_MESSAGE = 'Authentication required. Run `frontfriend login` to re-authenticate.';\n\nfunction getWithOptionalAuth(protocol, url, authToken, callback) {\n if (authToken) {\n return protocol.get(new URL(url), {\n headers: { authorization: `Bearer ${authToken}` },\n }, callback);\n }\n\n return protocol.get(url, callback);\n}\n\nfunction isAuthRedirect(response, body = '') {\n const location = response.headers?.location || '';\n return (\n response.statusCode === 401 ||\n response.statusCode === 403 ||\n (response.statusCode >= 300 && response.statusCode < 400 && location.includes('/sign-in')) ||\n String(body).trim().startsWith('/sign-in')\n );\n}\n\nfunction createHttpError(response, url, body = '') {\n if (isAuthRedirect(response, body)) {\n return new APIError(AUTH_REQUIRED_MESSAGE, response.statusCode, url);\n }\n let detail = response.statusMessage;\n try {\n const parsed = body ? JSON.parse(body) : null;\n if (parsed?.error) {\n detail = parsed.error;\n }\n const validationDetails = [\n ...(Array.isArray(parsed?.cssErrors)\n ? parsed.cssErrors.slice(0, 5).map(error => `${error.property}: ${error.className}`)\n : []),\n ...(Array.isArray(parsed?.schemaErrors)\n ? parsed.schemaErrors.slice(0, 5)\n : []),\n ];\n if (validationDetails.length > 0) {\n detail = `${detail} (${validationDetails.join('; ')})`;\n }\n } catch {\n // Keep the status text when the error body is not JSON.\n }\n return new APIError(\n `HTTP ${response.statusCode}: ${detail}`,\n response.statusCode,\n url\n );\n}\n\nclass APIClient {\n constructor(ffId, options = {}) {\n this.ffId = ffId;\n this.baseURL = options.baseURL || process.env[ENV_VARS.FF_API_URL] || DEFAULT_API_URL;\n this.legacyAuthToken = options.authToken || null;\n this.authToken = null;\n this.skipCredentials = options.skipCredentials || false;\n \n // Check if we should use local token reader\n if (process.env[ENV_VARS.FF_USE_LOCAL] === 'true') {\n console.log(' \uD83C\uDFE0 Using local token reader');\n this.localReader = new LocalTokenReader(ffId, options);\n }\n }\n\n /**\n * Fetch JSON data from a URL using native https module\n * @param {string} url - The URL to fetch\n * @param {Object} options - Fetch options\n * @param {boolean} options.returnHeaders - If true, return {data, headers} object\n * @returns {Promise<any>} Parsed JSON data or {data, headers} if returnHeaders is true\n */\n async getAuthToken() {\n this.authToken = await resolveAuthToken({\n baseURL: this.baseURL,\n envToken: process.env[ENV_VARS.FF_AUTH_TOKEN],\n legacyToken: this.legacyAuthToken,\n skipCredentials: this.skipCredentials,\n });\n return this.authToken;\n }\n\n async fetchJson(url, options = {}) {\n const authToken = await this.getAuthToken();\n return new Promise((resolve, reject) => {\n // Determine if we should use http or https\n const protocol = url.startsWith('https') ? https : http;\n\n getWithOptionalAuth(protocol, url, authToken, (response) => {\n let data = '';\n\n // Check for HTTP errors and redirects before waiting for a body. Some\n // tests and intermediaries do not send one.\n if (response.statusCode >= 300) {\n reject(createHttpError(response, url));\n return;\n }\n\n // Collect response chunks\n response.on('data', (chunk) => {\n data += chunk;\n });\n\n // Parse JSON when complete\n response.on('end', () => {\n try {\n const parsed = JSON.parse(data);\n\n // Return headers if requested\n if (options.returnHeaders) {\n resolve({\n data: parsed,\n headers: response.headers\n });\n } else {\n resolve(parsed);\n }\n } catch (error) {\n if (isAuthRedirect(response, data)) {\n reject(new APIError(AUTH_REQUIRED_MESSAGE, response.statusCode, url));\n return;\n }\n reject(new APIError(\n `Invalid JSON response: ${error.message}`,\n response.statusCode,\n url\n ));\n }\n });\n\n // Handle response errors\n response.on('error', (error) => {\n reject(new APIError(\n `Response error: ${error.message}`,\n response.statusCode,\n url\n ));\n });\n }).on('error', (error) => {\n // Handle network errors\n reject(new APIError(\n `Network error: ${error.message}`,\n 0,\n url\n ));\n });\n });\n }\n\n /**\n * Fetch raw content from a URL\n * @param {string} url - The URL to fetch\n * @returns {Promise<string>} Raw text content\n */\n async fetchRaw(url) {\n const authToken = await this.getAuthToken();\n return new Promise((resolve, reject) => {\n // Determine if we should use http or https\n const protocol = url.startsWith('https') ? https : http;\n \n getWithOptionalAuth(protocol, url, authToken, (response) => {\n let data = '';\n \n // Check for HTTP errors\n if (response.statusCode >= 400) {\n reject(new APIError(\n `HTTP ${response.statusCode}: ${response.statusMessage}`,\n response.statusCode,\n url\n ));\n return;\n }\n\n // Collect response chunks\n response.on('data', (chunk) => {\n data += chunk;\n });\n\n // Return raw data when complete\n response.on('end', () => {\n resolve(data);\n });\n\n // Handle response errors\n response.on('error', (error) => {\n reject(new APIError(\n `Response error: ${error.message}`,\n response.statusCode,\n url\n ));\n });\n }).on('error', (error) => {\n // Handle network errors\n reject(new APIError(\n `Network error: ${error.message}`,\n 0,\n url\n ));\n });\n });\n }\n\n /**\n * Fetch all token files (global, colors, semantic)\n * @returns {Promise<Object>} Object with all token data\n */\n async fetchTokens() {\n // Use local reader if available\n if (this.localReader) {\n return this.localReader.fetchTokens();\n }\n \n // First try the new design system endpoint\n try {\n const designSystemUrl = `${this.baseURL}/api/design-systems/${this.ffId}/tokens`;\n const tokensData = await this.fetchJson(designSystemUrl);\n \n // If we have the new format, parse it\n if (tokensData && tokensData.tokens) {\n const tokens = tokensData.tokens;\n \n // Extract specific token sets from the new format\n return {\n global: tokens['Global Tokens/Default'] || tokens['global'] || null,\n colors: tokens['Global Colors/Default'] || tokens['colors'] || null,\n semantic: tokens['Semantic/Light'] || tokens['semantic/light'] || null,\n semanticDark: tokens['Semantic/Dark'] || tokens['semantic/dark'] || null\n };\n }\n } catch (err) {\n // If design system is not synced (400 error), throw with clear message\n if (err.statusCode === 400) {\n throw new APIError(\n 'Design system not synced with Figma. Please sync tokens from Figma before using this design system.',\n 400,\n `${this.baseURL}/api/design-systems/${this.ffId}/tokens`\n );\n }\n // Failed to fetch from design system endpoint, falling back to legacy URLs\n }\n \n // Fall back to legacy token URLs\n // Use legacy API URL for backward compatibility\n const legacyBaseURL = LEGACY_API_URL;\n const urls = {\n global: `${legacyBaseURL}/${this.ffId}/global-tokens/default.json`,\n colors: `${legacyBaseURL}/${this.ffId}/global-colors/default.json`,\n semantic: `${legacyBaseURL}/${this.ffId}/semantic/light.json`,\n semanticDark: `${legacyBaseURL}/${this.ffId}/semantic/dark.json`\n };\n\n const results = await Promise.all([\n this.fetchJson(urls.global).catch(err => err.statusCode === 404 ? null : Promise.reject(err)),\n this.fetchJson(urls.colors).catch(err => err.statusCode === 404 ? null : Promise.reject(err)),\n this.fetchJson(urls.semantic).catch(err => err.statusCode === 404 ? null : Promise.reject(err)),\n this.fetchJson(urls.semanticDark).catch(err => err.statusCode === 404 ? null : Promise.reject(err))\n ]);\n\n return {\n global: results[0],\n colors: results[1],\n semantic: results[2],\n semanticDark: results[3]\n };\n }\n\n /**\n * Fetch pre-processed tokens from the design system endpoint\n * @param {Object} options - Fetch options\n * @param {string} options.tag - Tag name (e.g., 'dev', 'next', 'latest')\n * @param {string} options.version - Version label (e.g., 'v1.0.0')\n * @param {boolean} options.tailwindV4 - Request OKLCH/v4 color encoding so\n * generated utilities reference variables without an hsl() wrapper (#421)\n * @returns {Promise<Object|null>} Processed tokens ready for caching with metadata or null if not found\n */\n async fetchProcessedTokens(options = {}) {\n // Use local reader if available\n if (this.localReader) {\n return this.localReader.fetchProcessedTokens();\n }\n\n // Build URL with optional query parameters\n const url = new URL(`${this.baseURL}/api/design-systems/${this.ffId}/processed-tokens`);\n if (options.tag) {\n url.searchParams.append('tag', options.tag);\n }\n if (options.version) {\n url.searchParams.append('version', options.version);\n }\n if (options.tailwindV4) {\n // Tailwind v4 consumers need OKLCH-encoded variables so the generated\n // @utility rules can reference them directly. See issue #421.\n url.searchParams.append('tailwind', 'v4');\n }\n\n const processedUrl = url.toString();\n\n try {\n const result = await this.fetchJson(processedUrl, { returnHeaders: true });\n\n // Attach version metadata from response headers\n if (result.headers) {\n result.data.versionMetadata = {\n version: result.headers['x-frontfriend-version'],\n tag: result.headers['x-frontfriend-tag'],\n cached: result.headers['x-frontfriend-cached'] === 'true'\n };\n }\n\n return result.data;\n } catch (error) {\n if (error.statusCode === 404) {\n return null;\n }\n // If design system is not synced (400 error), throw with clear message\n if (error.statusCode === 400) {\n throw new APIError(\n 'Design system not synced with Figma. Please sync tokens from Figma before using this design system.',\n 400,\n processedUrl\n );\n }\n throw error;\n }\n }\n\n\n\n /**\n * Send JSON data to a URL using native http/https modules.\n * @param {string} url - The URL to send to\n * @param {string} method - HTTP method\n * @param {Object} body - JSON body\n * @returns {Promise<any>} Parsed JSON response or null for empty response\n */\n async sendJson(url, method, body) {\n const authToken = await this.getAuthToken();\n if (!authToken) {\n throw new APIError(AUTH_REQUIRED_MESSAGE, 401, url);\n }\n\n return new Promise((resolve, reject) => {\n const parsedUrl = new URL(url);\n const protocol = url.startsWith('https') ? https : http;\n const payload = JSON.stringify(body || {});\n const request = protocol.request({\n hostname: parsedUrl.hostname,\n port: parsedUrl.port,\n path: `${parsedUrl.pathname}${parsedUrl.search}`,\n method,\n headers: {\n 'content-type': 'application/json',\n 'content-length': Buffer.byteLength(payload),\n ...(authToken ? { authorization: `Bearer ${authToken}` } : {}),\n },\n }, (response) => {\n let data = '';\n response.on('data', chunk => { data += chunk; });\n response.on('end', () => {\n if (response.statusCode >= 300) {\n reject(createHttpError(response, url, data));\n return;\n }\n\n if (!data) {\n resolve(null);\n return;\n }\n try {\n resolve(JSON.parse(data));\n } catch (error) {\n if (isAuthRedirect(response, data)) {\n reject(new APIError(AUTH_REQUIRED_MESSAGE, response.statusCode, url));\n return;\n }\n reject(new APIError(\n `Invalid JSON response: ${error.message}`,\n response.statusCode,\n url\n ));\n }\n });\n });\n request.on('error', error => {\n reject(new APIError(`Network error: ${error.message}`, 0, url));\n });\n request.write(payload);\n request.end();\n });\n }\n\n /**\n * Push migrated component config to the cloud as a user override.\n * @param {Object} componentsConfig - FF-canonical component config\n * @returns {Promise<any>}\n */\n async pushComponentsConfig(componentsConfig, customCss, iconLibrary, options = {}) {\n const url = `${this.baseURL}/api/design-systems/${this.ffId}/components-config`;\n const payload = { componentsConfig };\n if (typeof customCss === 'string' && customCss.length > 0) {\n payload.customCss = customCss;\n }\n if (typeof iconLibrary === 'string' && iconLibrary.length > 0) {\n payload.iconLibrary = iconLibrary;\n }\n if (options.themeStudioRecipe && typeof options.themeStudioRecipe === 'object') {\n payload.themeStudioRecipe = options.themeStudioRecipe;\n }\n return this.sendJson(url, 'PUT', payload);\n }\n\n\n /**\n * Fetch components configuration\n * @returns {Promise<Object|null>} Components config or null if not found\n */\n async fetchComponentsConfig() {\n // Use local reader if available\n if (this.localReader) {\n return this.localReader.fetchComponentsConfig();\n }\n \n // Always use legacy URL for these endpoints\n const url = `${LEGACY_API_URL}/${this.ffId}/components-config.json`;\n try {\n return await this.fetchJson(url);\n } catch (error) {\n if (error.statusCode === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Fetch fonts configuration\n * @returns {Promise<Object|null>} Fonts object with font1, font2, etc. URLs or null\n */\n async fetchFonts() {\n // Use local reader if available\n if (this.localReader) {\n return this.localReader.fetchFonts();\n }\n \n // Always use legacy URL for these endpoints\n const url = `${LEGACY_API_URL}/${this.ffId}/font.json`;\n try {\n return await this.fetchJson(url);\n } catch (error) {\n if (error.statusCode === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Fetch icons configuration\n * @returns {Promise<Object|null>} Icons data or null if not found\n */\n async fetchIcons() {\n // Use local reader if available\n if (this.localReader) {\n return this.localReader.fetchIcons();\n }\n \n // Always use legacy URL for these endpoints\n const url = `${LEGACY_API_URL}/${this.ffId}/icons.json`;\n try {\n return await this.fetchJson(url);\n } catch (error) {\n if (error.statusCode === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Fetch version information\n * @returns {Promise<Object|null>} Version data or null if not found\n */\n async fetchVersion() {\n // Use local reader if available\n if (this.localReader) {\n return this.localReader.fetchVersion();\n }\n \n // Always use legacy URL for these endpoints\n const url = `${LEGACY_API_URL}/${this.ffId}/version.json`;\n try {\n return await this.fetchJson(url);\n } catch (error) {\n if (error.statusCode === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Fetch custom CSS\n * @returns {Promise<string|null>} Custom CSS string or null if not found\n */\n async fetchCustomCss() {\n // Use local reader if available\n if (this.localReader) {\n return this.localReader.fetchCustomCss();\n }\n \n // Always use legacy URL for these endpoints\n const url = `${LEGACY_API_URL}/${this.ffId}/custom.css`;\n try {\n return await this.fetchRaw(url);\n } catch (error) {\n if (error.statusCode === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Fetch plan metadata (plan type and allowed components)\n * @returns {Promise<Object|null>} Plan metadata or null if not found\n */\n async fetchPlanMetadata() {\n // Use local reader if available\n if (this.localReader) {\n if (process.env.FF_DEBUG) {\n console.log(' \u2192 Using local reader for plan metadata');\n }\n return this.localReader.fetchPlanMetadata();\n }\n \n // First try the saas app (processed-tokens endpoint) - this is the authoritative source\n const processedUrl = `${this.baseURL}/api/design-systems/${this.ffId}/processed-tokens`;\n try {\n if (process.env.FF_DEBUG) {\n console.log(` \u2192 Fetching plan metadata from saas app: ${processedUrl}`);\n }\n \n const processedData = await this.fetchJson(processedUrl);\n \n // Extract metadata from processed tokens response\n if (processedData && processedData.metadata) {\n const metadata = {\n planType: processedData.metadata.planType || 'full',\n allowedComponents: processedData.metadata.allowedComponents || null\n };\n \n if (process.env.FF_DEBUG) {\n console.log(` \u2192 Found plan metadata in saas app: ${metadata.planType}, allowed: ${metadata.allowedComponents ? metadata.allowedComponents.length + ' components' : 'all'}`);\n }\n \n return metadata;\n }\n } catch (saasError) {\n // If not found in saas app, try legacy server\n if (saasError.statusCode === 404) {\n if (process.env.FF_DEBUG) {\n console.log(' \u2192 ff-id not found in saas app, trying legacy server');\n }\n \n // Try legacy tokens server (these are always full plan - no trial concept)\n const tokensUrl = `${LEGACY_API_URL}/${this.ffId}/metadata`;\n try {\n if (process.env.FF_DEBUG) {\n console.log(` \u2192 Fetching from legacy server: ${tokensUrl}`);\n }\n const legacyMetadata = await this.fetchJson(tokensUrl);\n \n // Use the plan metadata from legacy server if available\n const metadata = {\n planType: legacyMetadata.planType || 'full',\n allowedComponents: legacyMetadata.allowedComponents || null\n };\n \n if (process.env.FF_DEBUG) {\n console.log(` \u2192 Found in legacy server: ${metadata.planType}, allowed: ${metadata.allowedComponents ? metadata.allowedComponents.length + ' components' : 'all'}`);\n }\n \n return metadata;\n } catch (legacyError) {\n if (legacyError.statusCode === 404) {\n // Not found in either place - DENY access\n if (process.env.FF_DEBUG) {\n console.log(' \u2192 ff-id not found in any server - access denied');\n }\n \n // Return a denied plan type instead of defaulting to full\n return {\n planType: 'denied',\n allowedComponents: [],\n error: 'Design system not found. Please ensure your ff-id is valid.'\n };\n }\n throw legacyError;\n }\n }\n throw saasError;\n }\n }\n}\n\nmodule.exports = { APIClient };\n"],
5
- "mappings": "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",
6
- "names": ["require_constants", "__commonJSMin", "exports", "module", "DEFAULT_API_URL", "LEGACY_API_URL", "CACHE_DIR_NAME", "CACHE_FILES", "ENV_VARS", "require_errors", "__commonJSMin", "exports", "module", "APIError", "message", "statusCode", "url", "CacheError", "operation", "ConfigError", "field", "ProcessingError", "token", "require_file_utils", "__commonJSMin", "exports", "module", "fs", "readJsonFileSafe", "filepath", "content", "error", "readFileSafe", "writeJsonFile", "data", "indent", "writeTextFile", "writeModuleExportsFile", "fileExists", "ensureDirectoryExists", "dirpath", "removeDirectory", "require_path_utils", "__commonJSMin", "exports", "module", "path", "fileExists", "findFileUpward", "filename", "startDir", "currentDir", "filePath", "findDirectoryUpward", "dirname", "validator", "possiblePaths", "maxLevels", "i", "parentDir", "dirPath", "findDirectoryWithPaths", "absolutePaths", "p", "require_local_token_reader", "__commonJSMin", "exports", "module", "path", "findDirectoryUpward", "readJsonFileSafe", "readFileSafe", "fileExists", "LocalTokenReader", "ffId", "options", "tokensPath", "dir", "folderMapPath", "folderMap", "figmaPath", "tokenPaths", "results", "key", "paths", "tokenPath", "content", "cachePath", "parseModuleExports", "moduleExports", "fakeModule", "cacheFiles", "processedData", "fileName", "type", "filePath", "value", "val", "require_credentials", "__commonJSMin", "exports", "module", "fs", "path", "os", "https", "http", "URL", "DEFAULT_API_URL", "CREDENTIALS_DIR", "CREDENTIALS_PATH", "getCredentialsPath", "readCredentials", "writeCredentials", "credentials", "deleteCredentials", "isExpired", "skewMs", "createAuthRefreshError", "message", "error", "postJson", "url", "body", "authToken", "resolve", "reject", "parsedUrl", "protocol", "payload", "request", "response", "data", "chunk", "redirectUrl", "parsed", "contentType", "apiError", "refreshCredentials", "baseURL", "refreshed", "resolveAuthToken", "options", "https", "http", "URL", "DEFAULT_API_URL", "LEGACY_API_URL", "ENV_VARS", "APIError", "LocalTokenReader", "resolveAuthToken", "AUTH_REQUIRED_MESSAGE", "getWithOptionalAuth", "protocol", "url", "authToken", "callback", "isAuthRedirect", "response", "body", "_a", "location", "createHttpError", "detail", "parsed", "validationDetails", "error", "APIClient", "ffId", "options", "resolve", "reject", "data", "chunk", "designSystemUrl", "tokensData", "tokens", "err", "legacyBaseURL", "urls", "results", "processedUrl", "result", "method", "parsedUrl", "payload", "request", "componentsConfig", "customCss", "iconLibrary", "processedData", "metadata", "saasError", "tokensUrl", "legacyMetadata", "legacyError"]
4
+ "sourcesContent": ["/**\n * Configuration constants for FrontFriend Tailwind v2\n */\n\n// API Configuration. The platform currently lives on the dev deployment \u2014\n// keep this as the CLI default so `frontfriend login`/init work zero-config.\nconst DEFAULT_API_URL = 'https://app.dev.frontfriend.dev';\nconst LEGACY_API_URL = 'https://registry-legacy.frontfriend.dev';\n\n// Cache Configuration\nconst CACHE_DIR_NAME = '.cache/frontfriend';\nconst CACHE_TTL_DAYS = 7;\nconst CACHE_TTL_MS = CACHE_TTL_DAYS * 24 * 60 * 60 * 1000;\n\n// File names\nconst CACHE_FILES = {\n JS: [\n 'tokens.js',\n 'variables.js',\n 'semanticVariables.js',\n 'semanticDarkVariables.js',\n 'safelist.js',\n 'custom.js'\n ],\n JSON: [\n 'fonts.json',\n 'icons.json',\n 'components-config.json',\n 'version.json',\n 'metadata.json'\n ]\n};\n\n// Environment variables\nconst ENV_VARS = {\n FF_ID: 'FF_ID',\n FF_API_URL: 'FF_API_URL',\n FF_USE_LOCAL: 'FF_USE_LOCAL',\n FF_AUTH_TOKEN: 'FF_AUTH_TOKEN'\n};\n\nmodule.exports = {\n DEFAULT_API_URL,\n LEGACY_API_URL,\n CACHE_DIR_NAME,\n CACHE_TTL_DAYS,\n CACHE_TTL_MS,\n CACHE_FILES,\n ENV_VARS\n};", "class APIError extends Error {\n constructor(message, statusCode, url) {\n super(message);\n this.name = 'APIError';\n this.statusCode = statusCode;\n this.url = url;\n this.code = `API_${statusCode}`;\n }\n}\n\nclass CacheError extends Error {\n constructor(message, operation) {\n super(message);\n this.name = 'CacheError';\n this.operation = operation;\n this.code = `CACHE_${operation.toUpperCase()}`;\n }\n}\n\nclass ConfigError extends Error {\n constructor(message, field) {\n super(message);\n this.name = 'ConfigError';\n this.field = field;\n // `field` is optional; guard so a missing field never crashes (and masks)\n // the real error with `Cannot read properties of undefined (toUpperCase)`.\n this.code = field ? `CONFIG_${String(field).toUpperCase()}` : 'CONFIG_ERROR';\n }\n}\n\nclass ProcessingError extends Error {\n constructor(message, token) {\n super(message);\n this.name = 'ProcessingError';\n this.token = token;\n this.code = 'PROCESSING_ERROR';\n }\n}\n\nmodule.exports = {\n APIError,\n CacheError,\n ConfigError,\n ProcessingError\n};", "const fs = require('fs');\n\n/**\n * Read a JSON file safely, returning null if file doesn't exist\n * @param {string} filepath - Path to the JSON file\n * @returns {Object|null} Parsed JSON or null if file not found\n * @throws {Error} If JSON is invalid\n */\nfunction readJsonFileSafe(filepath) {\n try {\n const content = fs.readFileSync(filepath, 'utf8');\n return JSON.parse(content);\n } catch (error) {\n if (error.code === 'ENOENT') {\n return null; // File not found, return null like API would return 404\n }\n throw error;\n }\n}\n\n/**\n * Read a file safely, returning null if file doesn't exist\n * Strips UTF-8 BOM if present (fixes Windows compatibility)\n * @param {string} filepath - Path to the file\n * @returns {string|null} File content or null if file not found\n * @throws {Error} For other file system errors\n */\nfunction readFileSafe(filepath) {\n try {\n const content = fs.readFileSync(filepath, 'utf8');\n // Strip UTF-8 BOM if present (Windows compatibility)\n return content.replace(/^\\uFEFF/, '');\n } catch (error) {\n if (error.code === 'ENOENT') {\n return null; // File not found\n }\n throw error;\n }\n}\n\n/**\n * Write JSON data to a file with proper formatting\n * @param {string} filepath - Path to write the file\n * @param {Object} data - Data to write\n * @param {number} indent - Indentation level (default: 2)\n */\nfunction writeJsonFile(filepath, data, indent = 2) {\n const content = JSON.stringify(data, null, indent);\n fs.writeFileSync(filepath, content, 'utf8');\n}\n\n/**\n * Write plain text content to a file\n * @param {string} filepath - Path to write the file\n * @param {string} content - Text content to write\n */\nfunction writeTextFile(filepath, content) {\n fs.writeFileSync(filepath, content, 'utf8');\n}\n\n/**\n * Write module.exports file with JSON data\n * @param {string} filepath - Path to write the file\n * @param {Object} data - Data to export\n */\nfunction writeModuleExportsFile(filepath, data) {\n // Handle empty data cases\n if (data === null || data === undefined || \n (typeof data === 'object' && Object.keys(data).length === 0) ||\n (Array.isArray(data) && data.length === 0)) {\n const emptyContent = Array.isArray(data) ? '[]' : '{}';\n const content = `module.exports = ${emptyContent};`;\n fs.writeFileSync(filepath, content, 'utf8');\n } else {\n const content = `module.exports = ${JSON.stringify(data, null, 2)};`;\n fs.writeFileSync(filepath, content, 'utf8');\n }\n}\n\n/**\n * Check if a file exists\n * @param {string} filepath - Path to check\n * @returns {boolean} True if file exists\n */\nfunction fileExists(filepath) {\n return fs.existsSync(filepath);\n}\n\n/**\n * Create directory recursively\n * @param {string} dirpath - Directory path to create\n */\nfunction ensureDirectoryExists(dirpath) {\n fs.mkdirSync(dirpath, { recursive: true });\n}\n\n/**\n * Remove directory recursively\n * @param {string} dirpath - Directory path to remove\n */\nfunction removeDirectory(dirpath) {\n fs.rmSync(dirpath, { recursive: true, force: true });\n}\n\nmodule.exports = {\n readJsonFileSafe,\n readFileSafe,\n writeJsonFile,\n writeTextFile,\n writeModuleExportsFile,\n fileExists,\n ensureDirectoryExists,\n removeDirectory\n};\n", "const path = require('path');\nconst { fileExists } = require('./file-utils');\n\n/**\n * Find a file by traversing up the directory tree\n * @param {string} filename - Name of the file to find\n * @param {string} startDir - Starting directory (defaults to cwd)\n * @returns {string|null} Full path to the file or null if not found\n */\nfunction findFileUpward(filename, startDir = process.cwd()) {\n let currentDir = startDir;\n \n while (currentDir !== path.parse(currentDir).root) {\n const filePath = path.join(currentDir, filename);\n \n if (fileExists(filePath)) {\n return filePath;\n }\n \n currentDir = path.dirname(currentDir);\n }\n \n return null;\n}\n\n/**\n * Find a directory by traversing up and checking multiple possible paths\n * @param {string} dirname - Name of the directory to find\n * @param {string} startDir - Starting directory (defaults to cwd)\n * @param {Function} validator - Optional function to validate the directory\n * @returns {string|null} Full path to the directory or null if not found\n */\nfunction findDirectoryUpward(dirname, startDir = process.cwd(), validator = null) {\n const possiblePaths = [];\n let currentDir = startDir;\n const maxLevels = 10; // Prevent infinite loop\n \n // Build list of possible paths\n for (let i = 0; i < maxLevels; i++) {\n // Direct path\n possiblePaths.push(path.join(currentDir, dirname));\n \n // Relative paths up to 3 levels\n if (i < 3) {\n possiblePaths.push(path.join(currentDir, '../'.repeat(i + 1) + dirname));\n }\n \n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) break; // Reached root\n currentDir = parentDir;\n }\n \n // Also check from module directory (for when running from node_modules)\n possiblePaths.push(path.join(__dirname, '../../../', dirname));\n \n // Find first existing directory that passes validation\n for (const dirPath of possiblePaths) {\n if (fileExists(dirPath)) {\n if (!validator || validator(dirPath)) {\n return dirPath;\n }\n }\n }\n \n return null;\n}\n\n/**\n * Find a directory with multiple possible relative paths\n * @param {string[]} possiblePaths - Array of possible paths to check\n * @param {string} startDir - Starting directory (defaults to cwd)\n * @returns {string|null} Full path to the directory or null if not found\n */\nfunction findDirectoryWithPaths(possiblePaths, startDir = process.cwd()) {\n // Build absolute paths from the start directory\n const absolutePaths = possiblePaths.map(p => {\n if (path.isAbsolute(p)) {\n return p;\n }\n return path.join(startDir, p);\n });\n \n // Find first existing path\n for (const dirPath of absolutePaths) {\n if (fileExists(dirPath)) {\n return dirPath;\n }\n }\n \n return null;\n}\n\nmodule.exports = {\n findFileUpward,\n findDirectoryUpward,\n findDirectoryWithPaths\n};", "const path = require('path');\nconst { findDirectoryUpward } = require('./path-utils');\nconst { readJsonFileSafe, readFileSafe, fileExists } = require('./file-utils');\n\n/**\n * LocalTokenReader - Reads tokens directly from the local file system\n * Mimics the APIClient interface but reads from apps/tokens directory\n */\nclass LocalTokenReader {\n constructor(ffId, options = {}) {\n this.ffId = ffId;\n this.tokensBasePath = options.tokensBasePath || this.findTokensPath();\n this.folderMap = this.loadFolderMap();\n this.projectFolder = this.folderMap[ffId];\n \n if (!this.projectFolder) {\n throw new Error(`No folder mapping found for ff-id: ${ffId}`);\n }\n \n this.projectPath = path.join(this.tokensBasePath, this.projectFolder);\n }\n\n /**\n * Find the tokens directory by looking for apps/tokens in parent directories\n */\n findTokensPath() {\n // Try to find apps/tokens first\n let tokensPath = findDirectoryUpward('apps/tokens', process.cwd(), (dir) => {\n return fileExists(path.join(dir, 'folderMap.json'));\n });\n \n // If not found, try just 'tokens'\n if (!tokensPath) {\n tokensPath = findDirectoryUpward('tokens', process.cwd(), (dir) => {\n return fileExists(path.join(dir, 'folderMap.json'));\n });\n }\n \n if (!tokensPath) {\n throw new Error('Could not find tokens directory with folderMap.json');\n }\n \n return tokensPath;\n }\n\n /**\n * Load the folder mapping from folderMap.json\n */\n loadFolderMap() {\n const folderMapPath = path.join(this.tokensBasePath, 'folderMap.json');\n const folderMap = readJsonFileSafe(folderMapPath);\n \n if (!folderMap) {\n throw new Error(`Failed to load folderMap.json: File not found`);\n }\n \n return folderMap;\n }\n\n /**\n * Fetch all token files (global, colors, semantic)\n * Mimics the APIClient.fetchTokens() method\n */\n async fetchTokens() {\n const figmaPath = path.join(this.projectPath, 'figma');\n \n // Try different possible paths for tokens\n const tokenPaths = {\n global: [\n path.join(figmaPath, 'Global Tokens', 'Default.json'),\n path.join(figmaPath, 'global.json')\n ],\n colors: [\n path.join(figmaPath, 'Global Colors', 'Default.json'),\n path.join(figmaPath, 'Global Colors', 'Light.json')\n ],\n semantic: [\n path.join(figmaPath, 'Semantic', 'Light.json'),\n path.join(figmaPath, 'Semantic', 'Default.json')\n ],\n semanticDark: [\n path.join(figmaPath, 'Semantic', 'Dark.json')\n ]\n };\n\n const results = {};\n \n // Try each possible path for each token type\n for (const [key, paths] of Object.entries(tokenPaths)) {\n for (const tokenPath of paths) {\n const content = readJsonFileSafe(tokenPath);\n if (content !== null) {\n results[key] = content;\n break; // Found it, no need to try other paths\n }\n }\n // If not found in any path, set to null\n if (!results[key]) {\n results[key] = null;\n }\n }\n\n return results;\n }\n\n /**\n * Fetch pre-processed tokens (if available in cache folder)\n */\n async fetchProcessedTokens() {\n const cachePath = path.join(this.projectPath, 'cache');\n \n if (!fileExists(cachePath)) {\n return null;\n }\n\n const parseModuleExports = (content) => {\n if (content === null) return null;\n\n const moduleExports = {};\n const fakeModule = { exports: moduleExports };\n const evalFunc = new Function('module', 'exports', content);\n evalFunc(fakeModule, moduleExports);\n return fakeModule.exports;\n };\n\n // Read all local cache files and normalize them to CacheManager.save() keys.\n const cacheFiles = {\n tokens: { fileName: 'hashedTokens.js', type: 'module' },\n variables: { fileName: 'hashedVariables.js', type: 'module' },\n semanticVariables: { fileName: 'hashedSemanticVariables.js', type: 'module' },\n semanticDarkVariables: { fileName: 'hashedSemanticDarkVariables.js', type: 'module' },\n safelist: { fileName: 'safelist.js', type: 'module' },\n custom: { fileName: 'custom.js', type: 'module' },\n fonts: { fileName: 'fonts.json', type: 'json' },\n icons: { fileName: 'icons.json', type: 'json' },\n componentsConfig: { fileName: 'encoded-config.json', type: 'json' },\n version: { fileName: 'version.json', type: 'json' }\n };\n\n const processedData = {};\n \n for (const [key, { fileName, type }] of Object.entries(cacheFiles)) {\n const filePath = path.join(cachePath, fileName);\n const value = type === 'module'\n ? parseModuleExports(readFileSafe(filePath))\n : readJsonFileSafe(filePath);\n\n if (value !== null) {\n processedData[key] = value;\n }\n }\n\n // Only return if we have at least some data\n const hasData = Object.values(processedData).some(val => val !== null);\n return hasData ? processedData : null;\n }\n\n /**\n * Fetch components configuration\n */\n async fetchComponentsConfig() {\n return readJsonFileSafe(path.join(this.projectPath, 'components-config.json'));\n }\n\n /**\n * Fetch fonts configuration\n */\n async fetchFonts() {\n return readJsonFileSafe(path.join(this.projectPath, 'font.json'));\n }\n\n /**\n * Fetch icons configuration\n */\n async fetchIcons() {\n return readJsonFileSafe(path.join(this.projectPath, 'icons.json'));\n }\n\n /**\n * Fetch version information\n */\n async fetchVersion() {\n return readJsonFileSafe(path.join(this.projectPath, 'version.json'));\n }\n\n /**\n * Fetch custom CSS\n */\n async fetchCustomCss() {\n return readFileSafe(path.join(this.projectPath, 'custom.css'));\n }\n\n /**\n * Fetch plan metadata\n */\n async fetchPlanMetadata() {\n const metadata = readJsonFileSafe(path.join(this.projectPath, 'metadata.json'));\n \n // Default to full plan if no metadata exists\n return metadata || {\n planType: 'full',\n allowedComponents: null\n };\n }\n\n // Compatibility methods to match APIClient interface\n fetchJson() {\n throw new Error('fetchJson is not implemented in LocalTokenReader. Use specific fetch methods.');\n }\n\n fetchRaw() {\n throw new Error('fetchRaw is not implemented in LocalTokenReader. Use specific fetch methods.');\n }\n}\n\nmodule.exports = { LocalTokenReader };\n", "const fs = require('fs');\nconst path = require('path');\nconst os = require('os');\nconst https = require('https');\nconst http = require('http');\nconst { URL } = require('url');\nconst { DEFAULT_API_URL } = require('./constants');\n\nconst CREDENTIALS_DIR = path.join(os.homedir(), '.frontfriend');\nconst CREDENTIALS_PATH = path.join(CREDENTIALS_DIR, 'credentials');\n\nfunction getCredentialsPath() {\n return CREDENTIALS_PATH;\n}\n\nfunction readCredentials() {\n try {\n if (!fs.existsSync(CREDENTIALS_PATH)) return null;\n return JSON.parse(fs.readFileSync(CREDENTIALS_PATH, 'utf8'));\n } catch {\n return null;\n }\n}\n\nfunction writeCredentials(credentials) {\n fs.mkdirSync(CREDENTIALS_DIR, { recursive: true, mode: 0o700 });\n fs.writeFileSync(CREDENTIALS_PATH, `${JSON.stringify(credentials, null, 2)}\\n`, { mode: 0o600 });\n try {\n fs.chmodSync(CREDENTIALS_PATH, 0o600);\n } catch {\n // Best effort on platforms that do not support chmod.\n }\n}\n\nfunction deleteCredentials() {\n if (fs.existsSync(CREDENTIALS_PATH)) {\n fs.unlinkSync(CREDENTIALS_PATH);\n return true;\n }\n return false;\n}\n\nfunction isExpired(credentials, skewMs = 60 * 1000) {\n return !credentials?.accessToken || !credentials.expiresAt || Date.now() + skewMs >= credentials.expiresAt;\n}\n\nfunction createAuthRefreshError(message) {\n const error = new Error(`${message}. Run \\`frontfriend login\\` to re-authenticate.`);\n error.code = 'FF_AUTH_REFRESH_FAILED';\n return error;\n}\n\nfunction postJson(url, body, authToken) {\n return new Promise((resolve, reject) => {\n const parsedUrl = new URL(url);\n const protocol = parsedUrl.protocol === 'https:' ? https : http;\n const payload = JSON.stringify(body || {});\n const request = protocol.request({\n hostname: parsedUrl.hostname,\n port: parsedUrl.port,\n path: `${parsedUrl.pathname}${parsedUrl.search}`,\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'content-length': Buffer.byteLength(payload),\n ...(authToken ? { authorization: `Bearer ${authToken}` } : {}),\n },\n }, response => {\n let data = '';\n response.on('data', chunk => { data += chunk; });\n response.on('end', () => {\n if (response.statusCode >= 300 && response.statusCode < 400) {\n const redirectUrl = response.headers.location ? ` to ${response.headers.location}` : '';\n const error = new Error(`HTTP ${response.statusCode}: redirected${redirectUrl}`);\n error.statusCode = response.statusCode;\n error.body = data;\n reject(error);\n return;\n }\n\n let parsed = null;\n try {\n parsed = data ? JSON.parse(data) : null;\n } catch (error) {\n const contentType = response.headers['content-type'] || 'unknown content-type';\n const apiError = new Error(\n `Expected JSON from FrontFriend API at ${url}, but received ${contentType} (HTTP ${response.statusCode}). ` +\n 'Check FF_API_URL or pass --api-url with the FrontFriend app URL.'\n );\n apiError.statusCode = response.statusCode;\n apiError.body = data;\n if (response.statusCode >= 400) {\n reject(apiError);\n return;\n }\n reject(apiError);\n return;\n }\n if (response.statusCode >= 400) {\n const error = new Error(parsed?.error_description || parsed?.error || `HTTP ${response.statusCode}`);\n error.statusCode = response.statusCode;\n error.body = parsed;\n reject(error);\n return;\n }\n resolve(parsed);\n });\n });\n request.on('error', reject);\n request.write(payload);\n request.end();\n });\n}\n\nasync function refreshCredentials(credentials, baseURL = DEFAULT_API_URL) {\n if (!credentials?.refreshToken || !credentials?.deviceId) {\n throw createAuthRefreshError('FrontFriend session expired');\n }\n\n let response;\n try {\n response = await postJson(`${baseURL}/api/plugin/token`, {\n grant_type: 'refresh_token',\n refresh_token: credentials.refreshToken,\n device_id: credentials.deviceId,\n });\n } catch (error) {\n throw createAuthRefreshError(error?.message || 'Could not refresh FrontFriend session');\n }\n\n if (!response?.access_token || !response?.refresh_token) {\n throw createAuthRefreshError('Could not refresh FrontFriend session');\n }\n\n const refreshed = {\n accessToken: response.access_token,\n refreshToken: response.refresh_token,\n deviceId: response.device_id || credentials.deviceId,\n expiresAt: Date.now() + (response.expires_in || 900) * 1000,\n refreshExpiresAt: Date.now() + (response.refresh_expires_in || 604800) * 1000,\n ffApiUrl: baseURL,\n };\n writeCredentials(refreshed);\n return refreshed;\n}\n\nasync function resolveAuthToken(options = {}) {\n if (!options.skipCredentials) {\n const credentials = readCredentials();\n if (credentials?.accessToken || credentials?.refreshToken) {\n const baseURL = options.baseURL || credentials.ffApiUrl || DEFAULT_API_URL;\n if (credentials.accessToken && !isExpired(credentials)) {\n return credentials.accessToken;\n }\n const refreshed = await refreshCredentials(credentials, baseURL);\n return refreshed.accessToken;\n }\n }\n\n if (options.envToken) return options.envToken;\n if (options.legacyToken) {\n if (!options.silent) {\n console.warn('\u26A0\uFE0F auth-token in frontfriend.config.js is deprecated. Run `frontfriend login` to store credentials outside the repo.');\n }\n return options.legacyToken;\n }\n return null;\n}\n\nmodule.exports = {\n getCredentialsPath,\n readCredentials,\n writeCredentials,\n deleteCredentials,\n isExpired,\n postJson,\n refreshCredentials,\n resolveAuthToken,\n createAuthRefreshError,\n};\n", "const https = require('https');\nconst http = require('http');\nconst { URL } = require('url');\nconst { DEFAULT_API_URL, LEGACY_API_URL, ENV_VARS } = require('./constants');\nconst { APIError } = require('./errors');\nconst { LocalTokenReader } = require('./local-token-reader');\nconst { resolveAuthToken } = require('./credentials');\n\nconst AUTH_REQUIRED_MESSAGE = 'Authentication required. Run `frontfriend login` to re-authenticate.';\n\nfunction getWithOptionalAuth(protocol, url, authToken, callback) {\n if (authToken) {\n return protocol.get(new URL(url), {\n headers: { authorization: `Bearer ${authToken}` },\n }, callback);\n }\n\n return protocol.get(url, callback);\n}\n\nfunction isAuthRedirect(response, body = '') {\n const location = response.headers?.location || '';\n return (\n response.statusCode === 401 ||\n response.statusCode === 403 ||\n (response.statusCode >= 300 && response.statusCode < 400 && location.includes('/sign-in')) ||\n String(body).trim().startsWith('/sign-in')\n );\n}\n\nfunction createHttpError(response, url, body = '') {\n if (isAuthRedirect(response, body)) {\n return new APIError(AUTH_REQUIRED_MESSAGE, response.statusCode, url);\n }\n let detail = response.statusMessage;\n try {\n const parsed = body ? JSON.parse(body) : null;\n if (parsed?.error) {\n detail = parsed.error;\n }\n const validationDetails = [\n ...(Array.isArray(parsed?.cssErrors)\n ? parsed.cssErrors.slice(0, 5).map(error => `${error.property}: ${error.className}`)\n : []),\n ...(Array.isArray(parsed?.schemaErrors)\n ? parsed.schemaErrors.slice(0, 5)\n : []),\n ];\n if (validationDetails.length > 0) {\n detail = `${detail} (${validationDetails.join('; ')})`;\n }\n } catch {\n // Keep the status text when the error body is not JSON.\n }\n return new APIError(\n `HTTP ${response.statusCode}: ${detail}`,\n response.statusCode,\n url\n );\n}\n\nclass APIClient {\n constructor(ffId, options = {}) {\n this.ffId = ffId;\n this.baseURL = options.baseURL || process.env[ENV_VARS.FF_API_URL] || DEFAULT_API_URL;\n this.legacyAuthToken = options.authToken || null;\n this.authToken = null;\n this.skipCredentials = options.skipCredentials || false;\n \n // Check if we should use local token reader\n if (process.env[ENV_VARS.FF_USE_LOCAL] === 'true') {\n console.log(' \uD83C\uDFE0 Using local token reader');\n this.localReader = new LocalTokenReader(ffId, options);\n }\n }\n\n /**\n * Fetch JSON data from a URL using native https module\n * @param {string} url - The URL to fetch\n * @param {Object} options - Fetch options\n * @param {boolean} options.returnHeaders - If true, return {data, headers} object\n * @returns {Promise<any>} Parsed JSON data or {data, headers} if returnHeaders is true\n */\n async getAuthToken() {\n this.authToken = await resolveAuthToken({\n baseURL: this.baseURL,\n envToken: process.env[ENV_VARS.FF_AUTH_TOKEN],\n legacyToken: this.legacyAuthToken,\n skipCredentials: this.skipCredentials,\n });\n return this.authToken;\n }\n\n async fetchJson(url, options = {}) {\n const authToken = await this.getAuthToken();\n return new Promise((resolve, reject) => {\n // Determine if we should use http or https\n const protocol = url.startsWith('https') ? https : http;\n\n getWithOptionalAuth(protocol, url, authToken, (response) => {\n let data = '';\n\n // Check for HTTP errors and redirects before waiting for a body. Some\n // tests and intermediaries do not send one.\n if (response.statusCode >= 300) {\n reject(createHttpError(response, url));\n return;\n }\n\n // Collect response chunks\n response.on('data', (chunk) => {\n data += chunk;\n });\n\n // Parse JSON when complete\n response.on('end', () => {\n try {\n const parsed = JSON.parse(data);\n\n // Return headers if requested\n if (options.returnHeaders) {\n resolve({\n data: parsed,\n headers: response.headers\n });\n } else {\n resolve(parsed);\n }\n } catch (error) {\n if (isAuthRedirect(response, data)) {\n reject(new APIError(AUTH_REQUIRED_MESSAGE, response.statusCode, url));\n return;\n }\n reject(new APIError(\n `Invalid JSON response: ${error.message}`,\n response.statusCode,\n url\n ));\n }\n });\n\n // Handle response errors\n response.on('error', (error) => {\n reject(new APIError(\n `Response error: ${error.message}`,\n response.statusCode,\n url\n ));\n });\n }).on('error', (error) => {\n // Handle network errors\n reject(new APIError(\n `Network error: ${error.message}`,\n 0,\n url\n ));\n });\n });\n }\n\n /**\n * Fetch raw content from a URL\n * @param {string} url - The URL to fetch\n * @returns {Promise<string>} Raw text content\n */\n async fetchRaw(url) {\n const authToken = await this.getAuthToken();\n return new Promise((resolve, reject) => {\n // Determine if we should use http or https\n const protocol = url.startsWith('https') ? https : http;\n \n getWithOptionalAuth(protocol, url, authToken, (response) => {\n let data = '';\n \n // Check for HTTP errors\n if (response.statusCode >= 400) {\n reject(new APIError(\n `HTTP ${response.statusCode}: ${response.statusMessage}`,\n response.statusCode,\n url\n ));\n return;\n }\n\n // Collect response chunks\n response.on('data', (chunk) => {\n data += chunk;\n });\n\n // Return raw data when complete\n response.on('end', () => {\n resolve(data);\n });\n\n // Handle response errors\n response.on('error', (error) => {\n reject(new APIError(\n `Response error: ${error.message}`,\n response.statusCode,\n url\n ));\n });\n }).on('error', (error) => {\n // Handle network errors\n reject(new APIError(\n `Network error: ${error.message}`,\n 0,\n url\n ));\n });\n });\n }\n\n /**\n * Fetch all token files (global, colors, semantic)\n * @returns {Promise<Object>} Object with all token data\n */\n async fetchTokens() {\n // Use local reader if available\n if (this.localReader) {\n return this.localReader.fetchTokens();\n }\n \n // First try the new design system endpoint\n try {\n const designSystemUrl = `${this.baseURL}/api/design-systems/${this.ffId}/tokens`;\n const tokensData = await this.fetchJson(designSystemUrl);\n \n // If we have the new format, parse it\n if (tokensData && tokensData.tokens) {\n const tokens = tokensData.tokens;\n \n // Extract specific token sets from the new format\n return {\n global: tokens['Global Tokens/Default'] || tokens['global'] || null,\n colors: tokens['Global Colors/Default'] || tokens['colors'] || null,\n semantic: tokens['Semantic/Light'] || tokens['semantic/light'] || null,\n semanticDark: tokens['Semantic/Dark'] || tokens['semantic/dark'] || null\n };\n }\n } catch (err) {\n // If design system is not synced (400 error), throw with clear message\n if (err.statusCode === 400) {\n throw new APIError(\n 'Design system not synced with Figma. Please sync tokens from Figma before using this design system.',\n 400,\n `${this.baseURL}/api/design-systems/${this.ffId}/tokens`\n );\n }\n // Failed to fetch from design system endpoint, falling back to legacy URLs\n }\n \n // Fall back to legacy token URLs\n // Use legacy API URL for backward compatibility\n const legacyBaseURL = LEGACY_API_URL;\n const urls = {\n global: `${legacyBaseURL}/${this.ffId}/global-tokens/default.json`,\n colors: `${legacyBaseURL}/${this.ffId}/global-colors/default.json`,\n semantic: `${legacyBaseURL}/${this.ffId}/semantic/light.json`,\n semanticDark: `${legacyBaseURL}/${this.ffId}/semantic/dark.json`\n };\n\n const results = await Promise.all([\n this.fetchJson(urls.global).catch(err => err.statusCode === 404 ? null : Promise.reject(err)),\n this.fetchJson(urls.colors).catch(err => err.statusCode === 404 ? null : Promise.reject(err)),\n this.fetchJson(urls.semantic).catch(err => err.statusCode === 404 ? null : Promise.reject(err)),\n this.fetchJson(urls.semanticDark).catch(err => err.statusCode === 404 ? null : Promise.reject(err))\n ]);\n\n return {\n global: results[0],\n colors: results[1],\n semantic: results[2],\n semanticDark: results[3]\n };\n }\n\n /**\n * Fetch pre-processed tokens from the design system endpoint\n * @param {Object} options - Fetch options\n * @param {string} options.tag - Tag name (e.g., 'dev', 'next', 'latest')\n * @param {string} options.version - Version label (e.g., 'v1.0.0')\n * @param {boolean} options.tailwindV4 - Request OKLCH/v4 color encoding so\n * generated utilities reference variables without an hsl() wrapper (#421)\n * @returns {Promise<Object|null>} Processed tokens ready for caching with metadata or null if not found\n */\n async fetchProcessedTokens(options = {}) {\n // Use local reader if available\n if (this.localReader) {\n return this.localReader.fetchProcessedTokens();\n }\n\n // Build URL with optional query parameters\n const url = new URL(`${this.baseURL}/api/design-systems/${this.ffId}/processed-tokens`);\n if (options.tag) {\n url.searchParams.append('tag', options.tag);\n }\n if (options.version) {\n url.searchParams.append('version', options.version);\n }\n if (options.tailwindV4) {\n // Tailwind v4 consumers need OKLCH-encoded variables so the generated\n // @utility rules can reference them directly. See issue #421.\n url.searchParams.append('tailwind', 'v4');\n }\n\n const processedUrl = url.toString();\n\n try {\n const result = await this.fetchJson(processedUrl, { returnHeaders: true });\n\n // Attach version metadata from response headers\n if (result.headers) {\n result.data.versionMetadata = {\n version: result.headers['x-frontfriend-version'],\n tag: result.headers['x-frontfriend-tag'],\n cached: result.headers['x-frontfriend-cached'] === 'true'\n };\n }\n\n return result.data;\n } catch (error) {\n if (error.statusCode === 404) {\n return null;\n }\n // If design system is not synced (400 error), throw with clear message\n if (error.statusCode === 400) {\n throw new APIError(\n 'Design system not synced with Figma. Please sync tokens from Figma before using this design system.',\n 400,\n processedUrl\n );\n }\n throw error;\n }\n }\n\n\n\n /**\n * Send JSON data to a URL using native http/https modules.\n * @param {string} url - The URL to send to\n * @param {string} method - HTTP method\n * @param {Object} body - JSON body\n * @returns {Promise<any>} Parsed JSON response or null for empty response\n */\n async sendJson(url, method, body) {\n const authToken = await this.getAuthToken();\n if (!authToken) {\n throw new APIError(AUTH_REQUIRED_MESSAGE, 401, url);\n }\n\n return new Promise((resolve, reject) => {\n const parsedUrl = new URL(url);\n const protocol = url.startsWith('https') ? https : http;\n const payload = JSON.stringify(body || {});\n const request = protocol.request({\n hostname: parsedUrl.hostname,\n port: parsedUrl.port,\n path: `${parsedUrl.pathname}${parsedUrl.search}`,\n method,\n headers: {\n 'content-type': 'application/json',\n 'content-length': Buffer.byteLength(payload),\n ...(authToken ? { authorization: `Bearer ${authToken}` } : {}),\n },\n }, (response) => {\n let data = '';\n response.on('data', chunk => { data += chunk; });\n response.on('end', () => {\n if (response.statusCode >= 300) {\n reject(createHttpError(response, url, data));\n return;\n }\n\n if (!data) {\n resolve(null);\n return;\n }\n try {\n resolve(JSON.parse(data));\n } catch (error) {\n if (isAuthRedirect(response, data)) {\n reject(new APIError(AUTH_REQUIRED_MESSAGE, response.statusCode, url));\n return;\n }\n reject(new APIError(\n `Invalid JSON response: ${error.message}`,\n response.statusCode,\n url\n ));\n }\n });\n });\n request.on('error', error => {\n reject(new APIError(`Network error: ${error.message}`, 0, url));\n });\n request.write(payload);\n request.end();\n });\n }\n\n /**\n * Push migrated component config to the cloud as a user override.\n * @param {Object} componentsConfig - FF-canonical component config\n * @returns {Promise<any>}\n */\n async pushComponentsConfig(componentsConfig, customCss, iconLibrary, options = {}) {\n const url = `${this.baseURL}/api/design-systems/${this.ffId}/components-config`;\n const payload = { componentsConfig };\n if (typeof customCss === 'string' && customCss.length > 0) {\n payload.customCss = customCss;\n }\n if (typeof iconLibrary === 'string' && iconLibrary.length > 0) {\n payload.iconLibrary = iconLibrary;\n }\n if (options.themeStudioRecipe && typeof options.themeStudioRecipe === 'object') {\n payload.themeStudioRecipe = options.themeStudioRecipe;\n }\n return this.sendJson(url, 'PUT', payload);\n }\n\n /**\n * Server-side migrate: upload the raw shadcn component sources; the platform\n * runs the transform (single source of truth), snapshots the inputs for\n * Restore, and persists the migrated config as a new version. Returns the\n * endpoint's { ok, snapshotId, summary, localActions, iconLibrary, version }.\n * Throws APIError on ko (4xx/5xx) so the caller can abort atomically.\n * @param {Object} payload - { framework, keepShadcnClasses, componentsJson, themeCss, files }\n * @returns {Promise<any>}\n */\n async migrateComponents(payload) {\n const url = `${this.baseURL}/api/design-systems/${this.ffId}/migrate`;\n return this.sendJson(url, 'POST', payload);\n }\n\n /**\n * List the design system's migrate snapshots (Restore points), newest first.\n * @returns {Promise<{snapshots: Array}>}\n */\n async listMigrationSnapshots() {\n const url = `${this.baseURL}/api/design-systems/${this.ffId}/migrate/snapshots`;\n return this.fetchJson(url);\n }\n\n /**\n * Resolve a single snapshot: manifest + a short-lived presigned URL for its bundle.\n * @param {string} snapshotId\n * @returns {Promise<{id: string, manifest: Array, url: string}>}\n */\n async getMigrationSnapshot(snapshotId) {\n const url = `${this.baseURL}/api/design-systems/${this.ffId}/migrate/snapshots/${snapshotId}`;\n return this.fetchJson(url);\n }\n\n\n /**\n * Fetch components configuration\n * @returns {Promise<Object|null>} Components config or null if not found\n */\n async fetchComponentsConfig() {\n // Use local reader if available\n if (this.localReader) {\n return this.localReader.fetchComponentsConfig();\n }\n \n // Always use legacy URL for these endpoints\n const url = `${LEGACY_API_URL}/${this.ffId}/components-config.json`;\n try {\n return await this.fetchJson(url);\n } catch (error) {\n if (error.statusCode === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Fetch fonts configuration\n * @returns {Promise<Object|null>} Fonts object with font1, font2, etc. URLs or null\n */\n async fetchFonts() {\n // Use local reader if available\n if (this.localReader) {\n return this.localReader.fetchFonts();\n }\n \n // Always use legacy URL for these endpoints\n const url = `${LEGACY_API_URL}/${this.ffId}/font.json`;\n try {\n return await this.fetchJson(url);\n } catch (error) {\n if (error.statusCode === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Fetch icons configuration\n * @returns {Promise<Object|null>} Icons data or null if not found\n */\n async fetchIcons() {\n // Use local reader if available\n if (this.localReader) {\n return this.localReader.fetchIcons();\n }\n \n // Always use legacy URL for these endpoints\n const url = `${LEGACY_API_URL}/${this.ffId}/icons.json`;\n try {\n return await this.fetchJson(url);\n } catch (error) {\n if (error.statusCode === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Fetch version information\n * @returns {Promise<Object|null>} Version data or null if not found\n */\n async fetchVersion() {\n // Use local reader if available\n if (this.localReader) {\n return this.localReader.fetchVersion();\n }\n \n // Always use legacy URL for these endpoints\n const url = `${LEGACY_API_URL}/${this.ffId}/version.json`;\n try {\n return await this.fetchJson(url);\n } catch (error) {\n if (error.statusCode === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Fetch custom CSS\n * @returns {Promise<string|null>} Custom CSS string or null if not found\n */\n async fetchCustomCss() {\n // Use local reader if available\n if (this.localReader) {\n return this.localReader.fetchCustomCss();\n }\n \n // Always use legacy URL for these endpoints\n const url = `${LEGACY_API_URL}/${this.ffId}/custom.css`;\n try {\n return await this.fetchRaw(url);\n } catch (error) {\n if (error.statusCode === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Fetch plan metadata (plan type and allowed components)\n * @returns {Promise<Object|null>} Plan metadata or null if not found\n */\n async fetchPlanMetadata() {\n // Use local reader if available\n if (this.localReader) {\n if (process.env.FF_DEBUG) {\n console.log(' \u2192 Using local reader for plan metadata');\n }\n return this.localReader.fetchPlanMetadata();\n }\n \n // First try the saas app (processed-tokens endpoint) - this is the authoritative source\n const processedUrl = `${this.baseURL}/api/design-systems/${this.ffId}/processed-tokens`;\n try {\n if (process.env.FF_DEBUG) {\n console.log(` \u2192 Fetching plan metadata from saas app: ${processedUrl}`);\n }\n \n const processedData = await this.fetchJson(processedUrl);\n \n // Extract metadata from processed tokens response\n if (processedData && processedData.metadata) {\n const metadata = {\n planType: processedData.metadata.planType || 'full',\n allowedComponents: processedData.metadata.allowedComponents || null\n };\n \n if (process.env.FF_DEBUG) {\n console.log(` \u2192 Found plan metadata in saas app: ${metadata.planType}, allowed: ${metadata.allowedComponents ? metadata.allowedComponents.length + ' components' : 'all'}`);\n }\n \n return metadata;\n }\n } catch (saasError) {\n // If not found in saas app, try legacy server\n if (saasError.statusCode === 404) {\n if (process.env.FF_DEBUG) {\n console.log(' \u2192 ff-id not found in saas app, trying legacy server');\n }\n \n // Try legacy tokens server (these are always full plan - no trial concept)\n const tokensUrl = `${LEGACY_API_URL}/${this.ffId}/metadata`;\n try {\n if (process.env.FF_DEBUG) {\n console.log(` \u2192 Fetching from legacy server: ${tokensUrl}`);\n }\n const legacyMetadata = await this.fetchJson(tokensUrl);\n \n // Use the plan metadata from legacy server if available\n const metadata = {\n planType: legacyMetadata.planType || 'full',\n allowedComponents: legacyMetadata.allowedComponents || null\n };\n \n if (process.env.FF_DEBUG) {\n console.log(` \u2192 Found in legacy server: ${metadata.planType}, allowed: ${metadata.allowedComponents ? metadata.allowedComponents.length + ' components' : 'all'}`);\n }\n \n return metadata;\n } catch (legacyError) {\n if (legacyError.statusCode === 404) {\n // Not found in either place - DENY access\n if (process.env.FF_DEBUG) {\n console.log(' \u2192 ff-id not found in any server - access denied');\n }\n \n // Return a denied plan type instead of defaulting to full\n return {\n planType: 'denied',\n allowedComponents: [],\n error: 'Design system not found. Please ensure your ff-id is valid.'\n };\n }\n throw legacyError;\n }\n }\n throw saasError;\n }\n }\n}\n\nmodule.exports = { APIClient };\n"],
5
+ "mappings": "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",
6
+ "names": ["require_constants", "__commonJSMin", "exports", "module", "DEFAULT_API_URL", "LEGACY_API_URL", "CACHE_DIR_NAME", "CACHE_FILES", "ENV_VARS", "require_errors", "__commonJSMin", "exports", "module", "APIError", "message", "statusCode", "url", "CacheError", "operation", "ConfigError", "field", "ProcessingError", "token", "require_file_utils", "__commonJSMin", "exports", "module", "fs", "readJsonFileSafe", "filepath", "content", "error", "readFileSafe", "writeJsonFile", "data", "indent", "writeTextFile", "writeModuleExportsFile", "fileExists", "ensureDirectoryExists", "dirpath", "removeDirectory", "require_path_utils", "__commonJSMin", "exports", "module", "path", "fileExists", "findFileUpward", "filename", "startDir", "currentDir", "filePath", "findDirectoryUpward", "dirname", "validator", "possiblePaths", "maxLevels", "i", "parentDir", "dirPath", "findDirectoryWithPaths", "absolutePaths", "p", "require_local_token_reader", "__commonJSMin", "exports", "module", "path", "findDirectoryUpward", "readJsonFileSafe", "readFileSafe", "fileExists", "LocalTokenReader", "ffId", "options", "tokensPath", "dir", "folderMapPath", "folderMap", "figmaPath", "tokenPaths", "results", "key", "paths", "tokenPath", "content", "cachePath", "parseModuleExports", "moduleExports", "fakeModule", "cacheFiles", "processedData", "fileName", "type", "filePath", "value", "val", "require_credentials", "__commonJSMin", "exports", "module", "fs", "path", "os", "https", "http", "URL", "DEFAULT_API_URL", "CREDENTIALS_DIR", "CREDENTIALS_PATH", "getCredentialsPath", "readCredentials", "writeCredentials", "credentials", "deleteCredentials", "isExpired", "skewMs", "createAuthRefreshError", "message", "error", "postJson", "url", "body", "authToken", "resolve", "reject", "parsedUrl", "protocol", "payload", "request", "response", "data", "chunk", "redirectUrl", "parsed", "contentType", "apiError", "refreshCredentials", "baseURL", "refreshed", "resolveAuthToken", "options", "https", "http", "URL", "DEFAULT_API_URL", "LEGACY_API_URL", "ENV_VARS", "APIError", "LocalTokenReader", "resolveAuthToken", "AUTH_REQUIRED_MESSAGE", "getWithOptionalAuth", "protocol", "url", "authToken", "callback", "isAuthRedirect", "response", "body", "_a", "location", "createHttpError", "detail", "parsed", "validationDetails", "error", "APIClient", "ffId", "options", "resolve", "reject", "data", "chunk", "designSystemUrl", "tokensData", "tokens", "err", "legacyBaseURL", "urls", "results", "processedUrl", "result", "method", "parsedUrl", "payload", "request", "componentsConfig", "customCss", "iconLibrary", "snapshotId", "processedData", "metadata", "saasError", "tokensUrl", "legacyMetadata", "legacyError"]
7
7
  }
@@ -145,14 +145,13 @@ class CacheManager {
145
145
  // Create cache directory
146
146
  ensureDirectoryExists(this.cacheDir);
147
147
 
148
- // Save metadata first
148
+ // Metadata is the cache commit marker. Write it last so an interrupted
149
+ // refresh is never advertised as a complete, current cache.
149
150
  const metadata = {
150
151
  timestamp: new Date().toISOString(),
151
152
  version: data.metadata?.version || '2.0.0',
152
153
  ffId: data.metadata?.ffId
153
154
  };
154
- writeJsonFile(this.metadataFile, metadata);
155
-
156
155
  // Save .js files
157
156
  const jsFiles = [
158
157
  'tokens',
@@ -200,6 +199,8 @@ class CacheManager {
200
199
  if (data.classesContent !== undefined) {
201
200
  writeTextFile(path.join(this.cacheDir, 'classes.css'), data.classesContent);
202
201
  }
202
+
203
+ writeJsonFile(this.metadataFile, metadata);
203
204
  } catch (error) {
204
205
  throw new CacheError(`Failed to save cache: ${error.message}`, 'write');
205
206
  }
@@ -0,0 +1,2 @@
1
+ var t='FrontFriend components configuration not found. Run "npx frontfriend init" or "npx frontfriend sync".',i="FrontFriend components configuration was not returned by the SaaS app. The cache was not updated.";function r(n){return n!==null&&typeof n=="object"&&!Array.isArray(n)}function e(n,o=t){if(!r(n)||Object.keys(n).length===0)throw new Error(o);return n}function s(n){if(!n.exists())throw new Error(t);let o=n.load();return{componentsConfig:e(o==null?void 0:o.componentsConfig),icons:r(o.icons)?o.icons:{}}}module.exports={CACHE_ERROR_MESSAGE:t,SAAS_ERROR_MESSAGE:i,assertComponentsConfig:e,loadCachedComponents:s};
2
+ //# sourceMappingURL=cached-components-config.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../lib/core/cached-components-config.js"],
4
+ "sourcesContent": ["const CACHE_ERROR_MESSAGE =\n 'FrontFriend components configuration not found. Run \"npx frontfriend init\" or \"npx frontfriend sync\".';\nconst SAAS_ERROR_MESSAGE =\n 'FrontFriend components configuration was not returned by the SaaS app. The cache was not updated.';\n\nfunction isPlainObject(value) {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction assertComponentsConfig(componentsConfig, message = CACHE_ERROR_MESSAGE) {\n if (!isPlainObject(componentsConfig) || Object.keys(componentsConfig).length === 0) {\n throw new Error(message);\n }\n\n return componentsConfig;\n}\n\nfunction loadCachedComponents(cacheManager) {\n if (!cacheManager.exists()) throw new Error(CACHE_ERROR_MESSAGE);\n\n const cache = cacheManager.load();\n const componentsConfig = assertComponentsConfig(cache?.componentsConfig);\n\n return {\n componentsConfig,\n icons: isPlainObject(cache.icons) ? cache.icons : {},\n };\n}\n\nmodule.exports = {\n CACHE_ERROR_MESSAGE,\n SAAS_ERROR_MESSAGE,\n assertComponentsConfig,\n loadCachedComponents,\n};\n"],
5
+ "mappings": "AAAA,IAAMA,EACJ,wGACIC,EACJ,oGAEF,SAASC,EAAcC,EAAO,CAC5B,OAAOA,IAAU,MAAQ,OAAOA,GAAU,UAAY,CAAC,MAAM,QAAQA,CAAK,CAC5E,CAEA,SAASC,EAAuBC,EAAkBC,EAAUN,EAAqB,CAC/E,GAAI,CAACE,EAAcG,CAAgB,GAAK,OAAO,KAAKA,CAAgB,EAAE,SAAW,EAC/E,MAAM,IAAI,MAAMC,CAAO,EAGzB,OAAOD,CACT,CAEA,SAASE,EAAqBC,EAAc,CAC1C,GAAI,CAACA,EAAa,OAAO,EAAG,MAAM,IAAI,MAAMR,CAAmB,EAE/D,IAAMS,EAAQD,EAAa,KAAK,EAGhC,MAAO,CACL,iBAHuBJ,EAAuBK,GAAA,YAAAA,EAAO,gBAAgB,EAIrE,MAAOP,EAAcO,EAAM,KAAK,EAAIA,EAAM,MAAQ,CAAC,CACrD,CACF,CAEA,OAAO,QAAU,CACf,oBAAAT,EACA,mBAAAC,EACA,uBAAAG,EACA,qBAAAG,CACF",
6
+ "names": ["CACHE_ERROR_MESSAGE", "SAAS_ERROR_MESSAGE", "isPlainObject", "value", "assertComponentsConfig", "componentsConfig", "message", "loadCachedComponents", "cacheManager", "cache"]
7
+ }