@ekanos/cli 0.1.8 → 0.1.10

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fa-free-names.js","sourceRoot":"","sources":["../../src/generated/fa-free-names.ts"],"names":[],"mappings":"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","sourcesContent":["// GENERATED FILE — do not hand-edit.\n//\n// Regenerate with `pnpm --filter @ekanos/cli generate:fa-free-names` after\n// @ekanos/ui's Free icon-name list, or @ekanos/harness's Pro→Free glyph\n// shim, changes. Source:\n// - @ekanos/ui's committed `fa-free-icon-names.generated.ts`, itself\n// generated from `@fortawesome/fontawesome-free@7.3.1`.\n// - @ekanos/harness's `styles/styles.src.css` Pro→Free shim comments.\n//\n// `@ekanos/cli` deliberately does not runtime-depend on `@ekanos/ui` or\n// `@ekanos/harness` (both are browser packages; the CLI is Node) — this\n// file is generated, dependency-free data so `ekanos validate`'s icon check\n// can still flag a Pro-only `fa-*` name without importing either.\n// Regenerated by this package's generate-fa-free-names script; drift against\n// the host's icon set is pinned by fa-free-names-drift.test.ts.\n\nexport const FA_FREE_VERSION = '7.3.1';\n\n/** Every icon name Font Awesome Free ships — NOT Fusion's set (Pro, a superset). */\nexport const FA_FREE_ICON_NAMES: ReadonlySet<string> = new Set([\n '11ty',\n '42-group',\n '500px',\n 'a11y-project',\n 'accessible-icon',\n 'accusoft',\n 'ad',\n 'address-book',\n 'address-card',\n 'adjust',\n 'adn',\n 'adversal',\n 'affiliatetheme',\n 'air-freshener',\n 'airbnb',\n 'alarm-clock',\n 'algolia',\n 'align-center',\n 'align-justify',\n 'align-left',\n 'align-right',\n 'alipay',\n 'allergies',\n 'amazon',\n 'amazon-pay',\n 'ambulance',\n 'american-sign-language-interpreting',\n 'amilia',\n 'anchor',\n 'anchor-circle-check',\n 'anchor-circle-exclamation',\n 'anchor-circle-xmark',\n 'anchor-lock',\n 'android',\n 'angellist',\n 'angle-double-down',\n 'angle-double-left',\n 'angle-double-right',\n 'angle-double-up',\n 'angle-down',\n 'angle-left',\n 'angle-right',\n 'angle-up',\n 'angles-down',\n 'angles-left',\n 'angles-right',\n 'angles-up',\n 'angry',\n 'angrycreative',\n 'angular',\n 'ankh',\n 'app-store',\n 'app-store-ios',\n 'apper',\n 'apple',\n 'apple-alt',\n 'apple-pay',\n 'apple-whole',\n 'aquarius',\n 'arch-linux',\n 'archive',\n 'archway',\n 'area-chart',\n 'aries',\n 'arrow-alt-circle-down',\n 'arrow-alt-circle-left',\n 'arrow-alt-circle-right',\n 'arrow-alt-circle-up',\n 'arrow-circle-down',\n 'arrow-circle-left',\n 'arrow-circle-right',\n 'arrow-circle-up',\n 'arrow-down',\n 'arrow-down-1-9',\n 'arrow-down-9-1',\n 'arrow-down-a-z',\n 'arrow-down-long',\n 'arrow-down-short-wide',\n 'arrow-down-up-across-line',\n 'arrow-down-up-lock',\n 'arrow-down-wide-short',\n 'arrow-down-z-a',\n 'arrow-left',\n 'arrow-left-long',\n 'arrow-left-rotate',\n 'arrow-pointer',\n 'arrow-right',\n 'arrow-right-arrow-left',\n 'arrow-right-from-bracket',\n 'arrow-right-from-file',\n 'arrow-right-long',\n 'arrow-right-rotate',\n 'arrow-right-to-bracket',\n 'arrow-right-to-city',\n 'arrow-right-to-file',\n 'arrow-rotate-back',\n 'arrow-rotate-backward',\n 'arrow-rotate-forward',\n 'arrow-rotate-left',\n 'arrow-rotate-right',\n 'arrow-trend-down',\n 'arrow-trend-up',\n 'arrow-turn-down',\n 'arrow-turn-up',\n 'arrow-up',\n 'arrow-up-1-9',\n 'arrow-up-9-1',\n 'arrow-up-a-z',\n 'arrow-up-from-bracket',\n 'arrow-up-from-ground-water',\n 'arrow-up-from-water-pump',\n 'arrow-up-long',\n 'arrow-up-right-dots',\n 'arrow-up-right-from-square',\n 'arrow-up-short-wide',\n 'arrow-up-wide-short',\n 'arrow-up-z-a',\n 'arrows',\n 'arrows-alt',\n 'arrows-alt-h',\n 'arrows-alt-v',\n 'arrows-down-to-line',\n 'arrows-down-to-people',\n 'arrows-h',\n 'arrows-left-right',\n 'arrows-left-right-to-line',\n 'arrows-rotate',\n 'arrows-spin',\n 'arrows-split-up-and-left',\n 'arrows-to-circle',\n 'arrows-to-dot',\n 'arrows-to-eye',\n 'arrows-turn-right',\n 'arrows-turn-to-dots',\n 'arrows-up-down',\n 'arrows-up-down-left-right',\n 'arrows-up-to-line',\n 'arrows-v',\n 'artstation',\n 'asl-interpreting',\n 'assistive-listening-systems',\n 'asymmetrik',\n 'atlas',\n 'atlassian',\n 'atom',\n 'audible',\n 'audio-description',\n 'austral-sign',\n 'automobile',\n 'autoprefixer',\n 'avianex',\n 'aviato',\n 'award',\n 'aws',\n 'baby',\n 'baby-carriage',\n 'backspace',\n 'backward',\n 'backward-fast',\n 'backward-step',\n 'bacon',\n 'bacteria',\n 'bacterium',\n 'bag-shopping',\n 'bahai',\n 'baht-sign',\n 'balance-scale',\n 'balance-scale-left',\n 'balance-scale-right',\n 'ban',\n 'ban-smoking',\n 'band-aid',\n 'bandage',\n 'bandcamp',\n 'bangladeshi-taka-sign',\n 'bank',\n 'bar-chart',\n 'barcode',\n 'bars',\n 'bars-progress',\n 'bars-staggered',\n 'baseball',\n 'baseball-ball',\n 'baseball-bat-ball',\n 'basket-shopping',\n 'basketball',\n 'basketball-ball',\n 'bath',\n 'bathtub',\n 'battery',\n 'battery-0',\n 'battery-2',\n 'battery-3',\n 'battery-4',\n 'battery-5',\n 'battery-car',\n 'battery-empty',\n 'battery-full',\n 'battery-half',\n 'battery-quarter',\n 'battery-three-quarters',\n 'battle-net',\n 'bed',\n 'bed-pulse',\n 'beer',\n 'beer-mug-empty',\n 'behance',\n 'behance-square',\n 'bell',\n 'bell-concierge',\n 'bell-slash',\n 'bezier-curve',\n 'bgg',\n 'bible',\n 'bicycle',\n 'biking',\n 'bilibili',\n 'bimobject',\n 'binoculars',\n 'biohazard',\n 'birthday-cake',\n 'bitbucket',\n 'bitcoin',\n 'bitcoin-sign',\n 'bity',\n 'black-tie',\n 'blackberry',\n 'blackboard',\n 'blender',\n 'blender-phone',\n 'blind',\n 'blog',\n 'blogger',\n 'blogger-b',\n 'bluesky',\n 'bluetooth',\n 'bluetooth-b',\n 'board-game-geek',\n 'bold',\n 'bolt',\n 'bolt-lightning',\n 'bomb',\n 'bone',\n 'bong',\n 'book',\n 'book-atlas',\n 'book-bible',\n 'book-bookmark',\n 'book-dead',\n 'book-journal-whills',\n 'book-medical',\n 'book-open',\n 'book-open-reader',\n 'book-quran',\n 'book-reader',\n 'book-skull',\n 'book-tanakh',\n 'bookmark',\n 'bootstrap',\n 'border-all',\n 'border-none',\n 'border-style',\n 'border-top-left',\n 'bore-hole',\n 'bots',\n 'bottle-droplet',\n 'bottle-water',\n 'bowl-food',\n 'bowl-rice',\n 'bowling-ball',\n 'box',\n 'box-archive',\n 'box-open',\n 'box-tissue',\n 'boxes',\n 'boxes-alt',\n 'boxes-packing',\n 'boxes-stacked',\n 'braille',\n 'brain',\n 'brave',\n 'brave-reverse',\n 'brazilian-real-sign',\n 'bread-slice',\n 'bridge',\n 'bridge-circle-check',\n 'bridge-circle-exclamation',\n 'bridge-circle-xmark',\n 'bridge-lock',\n 'bridge-water',\n 'briefcase',\n 'briefcase-clock',\n 'briefcase-medical',\n 'broadcast-tower',\n 'broom',\n 'broom-ball',\n 'brush',\n 'btc',\n 'bucket',\n 'buffer',\n 'bug',\n 'bug-slash',\n 'bugs',\n 'build-awesome',\n 'building',\n 'building-circle-arrow-right',\n 'building-circle-check',\n 'building-circle-exclamation',\n 'building-circle-xmark',\n 'building-columns',\n 'building-flag',\n 'building-lock',\n 'building-ngo',\n 'building-shield',\n 'building-un',\n 'building-user',\n 'building-wheat',\n 'bullhorn',\n 'bullseye',\n 'burger',\n 'burn',\n 'buromobelexperte',\n 'burst',\n 'bus',\n 'bus-alt',\n 'bus-side',\n 'bus-simple',\n 'business-time',\n 'buy-n-large',\n 'buysellads',\n 'cab',\n 'cable-car',\n 'cake',\n 'cake-candles',\n 'calculator',\n 'calendar',\n 'calendar-alt',\n 'calendar-check',\n 'calendar-day',\n 'calendar-days',\n 'calendar-minus',\n 'calendar-plus',\n 'calendar-times',\n 'calendar-week',\n 'calendar-xmark',\n 'camera',\n 'camera-alt',\n 'camera-retro',\n 'camera-rotate',\n 'campground',\n 'canadian-maple-leaf',\n 'cancel',\n 'cancer',\n 'candy-cane',\n 'cannabis',\n 'capricorn',\n 'capsules',\n 'car',\n 'car-alt',\n 'car-battery',\n 'car-burst',\n 'car-crash',\n 'car-on',\n 'car-rear',\n 'car-side',\n 'car-tunnel',\n 'caravan',\n 'caret-down',\n 'caret-left',\n 'caret-right',\n 'caret-square-down',\n 'caret-square-left',\n 'caret-square-right',\n 'caret-square-up',\n 'caret-up',\n 'carriage-baby',\n 'carrot',\n 'cart-arrow-down',\n 'cart-flatbed',\n 'cart-flatbed-suitcase',\n 'cart-plus',\n 'cart-shopping',\n 'cash-app',\n 'cash-register',\n 'cat',\n 'cc-amazon-pay',\n 'cc-amex',\n 'cc-apple-pay',\n 'cc-diners-club',\n 'cc-discover',\n 'cc-jcb',\n 'cc-mastercard',\n 'cc-paypal',\n 'cc-stripe',\n 'cc-visa',\n 'cedi-sign',\n 'cent-sign',\n 'centercode',\n 'centos',\n 'certificate',\n 'chain',\n 'chain-broken',\n 'chain-slash',\n 'chair',\n 'chalkboard',\n 'chalkboard-teacher',\n 'chalkboard-user',\n 'champagne-glasses',\n 'charging-station',\n 'chart-area',\n 'chart-bar',\n 'chart-column',\n 'chart-diagram',\n 'chart-gantt',\n 'chart-line',\n 'chart-pie',\n 'chart-simple',\n 'check',\n 'check-circle',\n 'check-double',\n 'check-square',\n 'check-to-slot',\n 'cheese',\n 'chess',\n 'chess-bishop',\n 'chess-board',\n 'chess-king',\n 'chess-knight',\n 'chess-pawn',\n 'chess-queen',\n 'chess-rook',\n 'chevron-circle-down',\n 'chevron-circle-left',\n 'chevron-circle-right',\n 'chevron-circle-up',\n 'chevron-down',\n 'chevron-left',\n 'chevron-right',\n 'chevron-up',\n 'child',\n 'child-combatant',\n 'child-dress',\n 'child-reaching',\n 'child-rifle',\n 'children',\n 'chrome',\n 'chromecast',\n 'church',\n 'circle',\n 'circle-arrow-down',\n 'circle-arrow-left',\n 'circle-arrow-right',\n 'circle-arrow-up',\n 'circle-check',\n 'circle-chevron-down',\n 'circle-chevron-left',\n 'circle-chevron-right',\n 'circle-chevron-up',\n 'circle-dollar-to-slot',\n 'circle-dot',\n 'circle-down',\n 'circle-exclamation',\n 'circle-h',\n 'circle-half-stroke',\n 'circle-info',\n 'circle-left',\n 'circle-minus',\n 'circle-nodes',\n 'circle-notch',\n 'circle-pause',\n 'circle-play',\n 'circle-plus',\n 'circle-question',\n 'circle-radiation',\n 'circle-right',\n 'circle-stop',\n 'circle-up',\n 'circle-user',\n 'circle-xmark',\n 'circle-zulip',\n 'city',\n 'clapperboard',\n 'claude',\n 'clinic-medical',\n 'clipboard',\n 'clipboard-check',\n 'clipboard-list',\n 'clipboard-question',\n 'clipboard-user',\n 'clock',\n 'clock-four',\n 'clock-rotate-left',\n 'clone',\n 'close',\n 'closed-captioning',\n 'closed-captioning-slash',\n 'cloud',\n 'cloud-arrow-down',\n 'cloud-arrow-up',\n 'cloud-bolt',\n 'cloud-download',\n 'cloud-download-alt',\n 'cloud-meatball',\n 'cloud-moon',\n 'cloud-moon-rain',\n 'cloud-rain',\n 'cloud-showers-heavy',\n 'cloud-showers-water',\n 'cloud-sun',\n 'cloud-sun-rain',\n 'cloud-upload',\n 'cloud-upload-alt',\n 'cloudflare',\n 'cloudscale',\n 'cloudsmith',\n 'cloudversify',\n 'clover',\n 'cmplid',\n 'cny',\n 'cocktail',\n 'code',\n 'code-branch',\n 'code-commit',\n 'code-compare',\n 'code-fork',\n 'code-merge',\n 'code-pull-request',\n 'codeberg',\n 'codepen',\n 'codiepie',\n 'coffee',\n 'cog',\n 'cogs',\n 'coins',\n 'colon-sign',\n 'columns',\n 'comment',\n 'comment-alt',\n 'comment-dollar',\n 'comment-dots',\n 'comment-medical',\n 'comment-nodes',\n 'comment-slash',\n 'comment-sms',\n 'commenting',\n 'comments',\n 'comments-dollar',\n 'compact-disc',\n 'compass',\n 'compass-drafting',\n 'compress',\n 'compress-alt',\n 'compress-arrows-alt',\n 'computer',\n 'computer-mouse',\n 'concierge-bell',\n 'confluence',\n 'connectdevelop',\n 'contact-book',\n 'contact-card',\n 'contao',\n 'cookie',\n 'cookie-bite',\n 'copilot',\n 'copy',\n 'copyright',\n 'cotton-bureau',\n 'couch',\n 'cow',\n 'cpanel',\n 'creative-commons',\n 'creative-commons-by',\n 'creative-commons-nc',\n 'creative-commons-nc-eu',\n 'creative-commons-nc-jp',\n 'creative-commons-nd',\n 'creative-commons-pd',\n 'creative-commons-pd-alt',\n 'creative-commons-remix',\n 'creative-commons-sa',\n 'creative-commons-sampling',\n 'creative-commons-sampling-plus',\n 'creative-commons-share',\n 'creative-commons-zero',\n 'credit-card',\n 'credit-card-alt',\n 'critical-role',\n 'crop',\n 'crop-alt',\n 'crop-simple',\n 'cross',\n 'crosshairs',\n 'crow',\n 'crown',\n 'crutch',\n 'cruzeiro-sign',\n 'css',\n 'css3',\n 'css3-alt',\n 'cube',\n 'cubes',\n 'cubes-stacked',\n 'cut',\n 'cutlery',\n 'cuttlefish',\n 'd-and-d',\n 'd-and-d-beyond',\n 'dailymotion',\n 'dart-lang',\n 'dashboard',\n 'dashcube',\n 'database',\n 'deaf',\n 'deafness',\n 'debian',\n 'dedent',\n 'deezer',\n 'delete-left',\n 'delicious',\n 'democrat',\n 'deploydog',\n 'deskpro',\n 'desktop',\n 'desktop-alt',\n 'dev',\n 'deviantart',\n 'devpost',\n 'dharmachakra',\n 'dhl',\n 'diagnoses',\n 'diagram-next',\n 'diagram-predecessor',\n 'diagram-project',\n 'diagram-successor',\n 'diamond',\n 'diamond-turn-right',\n 'diaspora',\n 'dice',\n 'dice-d20',\n 'dice-d6',\n 'dice-five',\n 'dice-four',\n 'dice-one',\n 'dice-six',\n 'dice-three',\n 'dice-two',\n 'digg',\n 'digging',\n 'digital-ocean',\n 'digital-tachograph',\n 'directions',\n 'discord',\n 'discourse',\n 'disease',\n 'display',\n 'disqus',\n 'divide',\n 'dizzy',\n 'dna',\n 'dochub',\n 'docker',\n 'dog',\n 'dolibarr',\n 'dolly',\n 'dolly-box',\n 'dolly-flatbed',\n 'donate',\n 'dong-sign',\n 'door-closed',\n 'door-open',\n 'dot-circle',\n 'dove',\n 'down-left-and-up-right-to-center',\n 'down-long',\n 'download',\n 'draft2digital',\n 'drafting-compass',\n 'dragon',\n 'draw-polygon',\n 'dribbble',\n 'dribbble-square',\n 'drivers-license',\n 'dropbox',\n 'droplet',\n 'droplet-slash',\n 'drum',\n 'drum-steelpan',\n 'drumstick-bite',\n 'drupal',\n 'dumbbell',\n 'dumpster',\n 'dumpster-fire',\n 'dungeon',\n 'duolingo',\n 'dyalog',\n 'ear-deaf',\n 'ear-listen',\n 'earlybirds',\n 'earth',\n 'earth-africa',\n 'earth-america',\n 'earth-americas',\n 'earth-asia',\n 'earth-europe',\n 'earth-oceania',\n 'ebay',\n 'edge',\n 'edge-legacy',\n 'edit',\n 'egg',\n 'eject',\n 'elementor',\n 'elevator',\n 'eleventy',\n 'ellipsis',\n 'ellipsis-h',\n 'ellipsis-v',\n 'ellipsis-vertical',\n 'ello',\n 'ember',\n 'empire',\n 'envelope',\n 'envelope-circle-check',\n 'envelope-open',\n 'envelope-open-text',\n 'envelope-square',\n 'envelopes-bulk',\n 'envira',\n 'eraser',\n 'erlang',\n 'ethereum',\n 'ethernet',\n 'etsy',\n 'eur',\n 'euro',\n 'euro-sign',\n 'evernote',\n 'exchange',\n 'exchange-alt',\n 'exclamation-circle',\n 'exclamation-triangle',\n 'expand',\n 'expand-alt',\n 'expand-arrows-alt',\n 'expeditedssl',\n 'explosion',\n 'external-link',\n 'external-link-alt',\n 'external-link-square',\n 'external-link-square-alt',\n 'eye',\n 'eye-dropper',\n 'eye-dropper-empty',\n 'eye-low-vision',\n 'eye-slash',\n 'eyedropper',\n 'face-angry',\n 'face-dizzy',\n 'face-flushed',\n 'face-frown',\n 'face-frown-open',\n 'face-grimace',\n 'face-grin',\n 'face-grin-beam',\n 'face-grin-beam-sweat',\n 'face-grin-hearts',\n 'face-grin-squint',\n 'face-grin-squint-tears',\n 'face-grin-stars',\n 'face-grin-tears',\n 'face-grin-tongue',\n 'face-grin-tongue-squint',\n 'face-grin-tongue-wink',\n 'face-grin-wide',\n 'face-grin-wink',\n 'face-kiss',\n 'face-kiss-beam',\n 'face-kiss-wink-heart',\n 'face-laugh',\n 'face-laugh-beam',\n 'face-laugh-squint',\n 'face-laugh-wink',\n 'face-meh',\n 'face-meh-blank',\n 'face-rolling-eyes',\n 'face-sad-cry',\n 'face-sad-tear',\n 'face-smile',\n 'face-smile-beam',\n 'face-smile-wink',\n 'face-surprise',\n 'face-tired',\n 'facebook',\n 'facebook-f',\n 'facebook-messenger',\n 'facebook-square',\n 'fan',\n 'fantasy-flight-games',\n 'fast-backward',\n 'fast-forward',\n 'faucet',\n 'faucet-drip',\n 'fax',\n 'feather',\n 'feather-alt',\n 'feather-pointed',\n 'fedex',\n 'fediverse',\n 'fedora',\n 'feed',\n 'female',\n 'ferry',\n 'fighter-jet',\n 'figma',\n 'file',\n 'file-alt',\n 'file-archive',\n 'file-arrow-down',\n 'file-arrow-up',\n 'file-audio',\n 'file-circle-check',\n 'file-circle-exclamation',\n 'file-circle-minus',\n 'file-circle-plus',\n 'file-circle-question',\n 'file-circle-xmark',\n 'file-clipboard',\n 'file-code',\n 'file-contract',\n 'file-csv',\n 'file-download',\n 'file-edit',\n 'file-excel',\n 'file-export',\n 'file-fragment',\n 'file-half-dashed',\n 'file-image',\n 'file-import',\n 'file-invoice',\n 'file-invoice-dollar',\n 'file-lines',\n 'file-medical',\n 'file-medical-alt',\n 'file-pdf',\n 'file-pen',\n 'file-powerpoint',\n 'file-prescription',\n 'file-shield',\n 'file-signature',\n 'file-text',\n 'file-upload',\n 'file-video',\n 'file-waveform',\n 'file-word',\n 'file-zipper',\n 'files-pinwheel',\n 'fill',\n 'fill-drip',\n 'film',\n 'film-alt',\n 'film-simple',\n 'filter',\n 'filter-circle-dollar',\n 'filter-circle-xmark',\n 'fingerprint',\n 'fire',\n 'fire-alt',\n 'fire-burner',\n 'fire-extinguisher',\n 'fire-flame-curved',\n 'fire-flame-simple',\n 'firefox',\n 'firefox-browser',\n 'first-aid',\n 'first-order',\n 'first-order-alt',\n 'firstdraft',\n 'fish',\n 'fish-fins',\n 'fist-raised',\n 'flag',\n 'flag-checkered',\n 'flag-usa',\n 'flask',\n 'flask-vial',\n 'flickr',\n 'flipboard',\n 'floppy-disk',\n 'florin-sign',\n 'flushed',\n 'flutter',\n 'fly',\n 'folder',\n 'folder-blank',\n 'folder-closed',\n 'folder-minus',\n 'folder-open',\n 'folder-plus',\n 'folder-tree',\n 'font',\n 'font-awesome',\n 'font-awesome-alt',\n 'font-awesome-flag',\n 'font-awesome-logo-full',\n 'fonticons',\n 'fonticons-fi',\n 'football',\n 'football-ball',\n 'forgejo',\n 'fort-awesome',\n 'fort-awesome-alt',\n 'forumbee',\n 'forward',\n 'forward-fast',\n 'forward-step',\n 'foursquare',\n 'franc-sign',\n 'free-code-camp',\n 'freebsd',\n 'frog',\n 'frown',\n 'frown-open',\n 'fulcrum',\n 'funnel-dollar',\n 'futbol',\n 'futbol-ball',\n 'galactic-republic',\n 'galactic-senate',\n 'gamepad',\n 'gas-pump',\n 'gauge',\n 'gauge-high',\n 'gauge-med',\n 'gauge-simple',\n 'gauge-simple-high',\n 'gauge-simple-med',\n 'gavel',\n 'gbp',\n 'gear',\n 'gears',\n 'gem',\n 'gemini',\n 'genderless',\n 'get-pocket',\n 'gg',\n 'gg-circle',\n 'ghost',\n 'gift',\n 'gifts',\n 'git',\n 'git-alt',\n 'git-square',\n 'gitee',\n 'github',\n 'github-alt',\n 'github-square',\n 'gitkraken',\n 'gitlab',\n 'gitlab-square',\n 'gitter',\n 'glass-cheers',\n 'glass-martini',\n 'glass-martini-alt',\n 'glass-water',\n 'glass-water-droplet',\n 'glass-whiskey',\n 'glasses',\n 'glide',\n 'glide-g',\n 'globaleaks',\n 'globe',\n 'globe-africa',\n 'globe-americas',\n 'globe-asia',\n 'globe-europe',\n 'globe-oceania',\n 'gofore',\n 'golang',\n 'golf-ball',\n 'golf-ball-tee',\n 'goodreads',\n 'goodreads-g',\n 'google',\n 'google-drive',\n 'google-pay',\n 'google-play',\n 'google-plus',\n 'google-plus-g',\n 'google-plus-square',\n 'google-scholar',\n 'google-wallet',\n 'gopuram',\n 'graduation-cap',\n 'gratipay',\n 'grav',\n 'greater-than-equal',\n 'grid-horizontal',\n 'grid-vertical',\n 'grimace',\n 'grin',\n 'grin-alt',\n 'grin-beam',\n 'grin-beam-sweat',\n 'grin-hearts',\n 'grin-squint',\n 'grin-squint-tears',\n 'grin-stars',\n 'grin-tears',\n 'grin-tongue',\n 'grin-tongue-squint',\n 'grin-tongue-wink',\n 'grin-wink',\n 'grip',\n 'grip-horizontal',\n 'grip-lines',\n 'grip-lines-vertical',\n 'grip-vertical',\n 'gripfire',\n 'group-arrows-rotate',\n 'grunt',\n 'guarani-sign',\n 'guilded',\n 'guitar',\n 'gulp',\n 'gun',\n 'h-square',\n 'hacker-news',\n 'hacker-news-square',\n 'hackerrank',\n 'hamburger',\n 'hammer',\n 'hamsa',\n 'hand',\n 'hand-back-fist',\n 'hand-dots',\n 'hand-fist',\n 'hand-holding',\n 'hand-holding-dollar',\n 'hand-holding-droplet',\n 'hand-holding-hand',\n 'hand-holding-heart',\n 'hand-holding-medical',\n 'hand-holding-usd',\n 'hand-holding-water',\n 'hand-lizard',\n 'hand-middle-finger',\n 'hand-paper',\n 'hand-peace',\n 'hand-point-down',\n 'hand-point-left',\n 'hand-point-right',\n 'hand-point-up',\n 'hand-pointer',\n 'hand-rock',\n 'hand-scissors',\n 'hand-sparkles',\n 'hand-spock',\n 'handcuffs',\n 'hands',\n 'hands-american-sign-language-interpreting',\n 'hands-asl-interpreting',\n 'hands-bound',\n 'hands-bubbles',\n 'hands-clapping',\n 'hands-helping',\n 'hands-holding',\n 'hands-holding-child',\n 'hands-holding-circle',\n 'hands-praying',\n 'hands-wash',\n 'handshake',\n 'handshake-alt',\n 'handshake-alt-slash',\n 'handshake-angle',\n 'handshake-simple',\n 'handshake-simple-slash',\n 'handshake-slash',\n 'hanukiah',\n 'hard-drive',\n 'hard-hat',\n 'hard-of-hearing',\n 'hashnode',\n 'hat-cowboy',\n 'hat-cowboy-side',\n 'hat-hard',\n 'hat-wizard',\n 'haykal',\n 'hdd',\n 'head-side-cough',\n 'head-side-cough-slash',\n 'head-side-mask',\n 'head-side-virus',\n 'header',\n 'heading',\n 'headphones',\n 'headphones-alt',\n 'headphones-simple',\n 'headset',\n 'heart',\n 'heart-broken',\n 'heart-circle-bolt',\n 'heart-circle-check',\n 'heart-circle-exclamation',\n 'heart-circle-minus',\n 'heart-circle-plus',\n 'heart-circle-xmark',\n 'heart-crack',\n 'heart-music-camera-bolt',\n 'heart-pulse',\n 'heartbeat',\n 'helicopter',\n 'helicopter-symbol',\n 'helmet-safety',\n 'helmet-un',\n 'heptagon',\n 'hexagon',\n 'hexagon-nodes',\n 'hexagon-nodes-bolt',\n 'highlighter',\n 'hiking',\n 'hill-avalanche',\n 'hill-rockslide',\n 'hippo',\n 'hips',\n 'hire-a-helper',\n 'history',\n 'hive',\n 'hockey-puck',\n 'holly-berry',\n 'home',\n 'home-alt',\n 'home-lg',\n 'home-lg-alt',\n 'home-user',\n 'hooli',\n 'hornbill',\n 'horse',\n 'horse-head',\n 'hospital',\n 'hospital-alt',\n 'hospital-symbol',\n 'hospital-user',\n 'hospital-wide',\n 'hot-tub',\n 'hot-tub-person',\n 'hotdog',\n 'hotel',\n 'hotjar',\n 'hourglass',\n 'hourglass-1',\n 'hourglass-2',\n 'hourglass-3',\n 'hourglass-empty',\n 'hourglass-end',\n 'hourglass-half',\n 'hourglass-start',\n 'house',\n 'house-chimney',\n 'house-chimney-crack',\n 'house-chimney-medical',\n 'house-chimney-user',\n 'house-chimney-window',\n 'house-circle-check',\n 'house-circle-exclamation',\n 'house-circle-xmark',\n 'house-crack',\n 'house-damage',\n 'house-fire',\n 'house-flag',\n 'house-flood-water',\n 'house-flood-water-circle-arrow-right',\n 'house-laptop',\n 'house-lock',\n 'house-medical',\n 'house-medical-circle-check',\n 'house-medical-circle-exclamation',\n 'house-medical-circle-xmark',\n 'house-medical-flag',\n 'house-signal',\n 'house-tsunami',\n 'house-user',\n 'houzz',\n 'hryvnia',\n 'hryvnia-sign',\n 'html5',\n 'hubspot',\n 'hugging-face',\n 'hurricane',\n 'i-cursor',\n 'ice-cream',\n 'icicles',\n 'icons',\n 'id-badge',\n 'id-card',\n 'id-card-alt',\n 'id-card-clip',\n 'ideal',\n 'igloo',\n 'ils',\n 'image',\n 'image-portrait',\n 'images',\n 'imdb',\n 'inbox',\n 'indent',\n 'indian-rupee',\n 'indian-rupee-sign',\n 'industry',\n 'infinity',\n 'info',\n 'info-circle',\n 'innosoft',\n 'inr',\n 'instagram',\n 'instagram-square',\n 'instalod',\n 'institution',\n 'intercom',\n 'internet-archive',\n 'internet-explorer',\n 'invision',\n 'ioxhost',\n 'italic',\n 'itch-io',\n 'itunes',\n 'itunes-note',\n 'jar',\n 'jar-wheat',\n 'java',\n 'jedi',\n 'jedi-order',\n 'jenkins',\n 'jet-fighter',\n 'jet-fighter-up',\n 'jira',\n 'joget',\n 'joint',\n 'joomla',\n 'journal-whills',\n 'jpy',\n 'js',\n 'js-square',\n 'jsfiddle',\n 'jug-detergent',\n 'julia',\n 'jxl',\n 'kaaba',\n 'kaggle',\n 'kakao-talk',\n 'key',\n 'keybase',\n 'keyboard',\n 'keycdn',\n 'khanda',\n 'kickstarter',\n 'kickstarter-k',\n 'kip-sign',\n 'kiss',\n 'kiss-beam',\n 'kiss-wink-heart',\n 'kit-medical',\n 'kitchen-set',\n 'kiwi-bird',\n 'ko-fi',\n 'korvue',\n 'krw',\n 'kubernetes',\n 'ladder-water',\n 'land-mine-on',\n 'landmark',\n 'landmark-alt',\n 'landmark-dome',\n 'landmark-flag',\n 'language',\n 'laptop',\n 'laptop-code',\n 'laptop-file',\n 'laptop-house',\n 'laptop-medical',\n 'laravel',\n 'lari-sign',\n 'lastfm',\n 'lastfm-square',\n 'laugh',\n 'laugh-beam',\n 'laugh-squint',\n 'laugh-wink',\n 'layer-group',\n 'leaf',\n 'leanpub',\n 'leetcode',\n 'left-long',\n 'left-right',\n 'legal',\n 'lemon',\n 'leo',\n 'less',\n 'less-than-equal',\n 'lets-encrypt',\n 'letterboxd',\n 'level-down',\n 'level-down-alt',\n 'level-up',\n 'level-up-alt',\n 'libra',\n 'life-ring',\n 'lightbulb',\n 'line',\n 'line-chart',\n 'lines-leaning',\n 'link',\n 'link-slash',\n 'linkedin',\n 'linkedin-in',\n 'linktree',\n 'linode',\n 'linux',\n 'lira-sign',\n 'list',\n 'list-1-2',\n 'list-alt',\n 'list-check',\n 'list-dots',\n 'list-numeric',\n 'list-ol',\n 'list-squares',\n 'list-ul',\n 'litecoin-sign',\n 'location',\n 'location-arrow',\n 'location-crosshairs',\n 'location-dot',\n 'location-pin',\n 'location-pin-lock',\n 'lock',\n 'lock-open',\n 'locust',\n 'long-arrow-alt-down',\n 'long-arrow-alt-left',\n 'long-arrow-alt-right',\n 'long-arrow-alt-up',\n 'long-arrow-down',\n 'long-arrow-left',\n 'long-arrow-right',\n 'long-arrow-up',\n 'lotus',\n 'low-vision',\n 'luggage-cart',\n 'lumon',\n 'lumon-drop',\n 'lungs',\n 'lungs-virus',\n 'lyft',\n 'magento',\n 'magic',\n 'magic-wand-sparkles',\n 'magnet',\n 'magnifying-glass',\n 'magnifying-glass-arrow-right',\n 'magnifying-glass-chart',\n 'magnifying-glass-dollar',\n 'magnifying-glass-location',\n 'magnifying-glass-minus',\n 'magnifying-glass-plus',\n 'mail-bulk',\n 'mail-forward',\n 'mail-reply',\n 'mail-reply-all',\n 'mailchimp',\n 'male',\n 'manat-sign',\n 'mandalorian',\n 'map',\n 'map-location',\n 'map-location-dot',\n 'map-marked',\n 'map-marked-alt',\n 'map-marker',\n 'map-marker-alt',\n 'map-pin',\n 'map-signs',\n 'markdown',\n 'marker',\n 'mars',\n 'mars-and-venus',\n 'mars-and-venus-burst',\n 'mars-double',\n 'mars-stroke',\n 'mars-stroke-h',\n 'mars-stroke-right',\n 'mars-stroke-up',\n 'mars-stroke-v',\n 'martini-glass',\n 'martini-glass-citrus',\n 'martini-glass-empty',\n 'mask',\n 'mask-face',\n 'mask-ventilator',\n 'masks-theater',\n 'mastodon',\n 'matrix',\n 'mattermost',\n 'mattress-pillow',\n 'maxcdn',\n 'maximize',\n 'mdb',\n 'medal',\n 'medapps',\n 'medium',\n 'medium-m',\n 'medkit',\n 'medrt',\n 'meetup',\n 'megaport',\n 'meh',\n 'meh-blank',\n 'meh-rolling-eyes',\n 'memory',\n 'mendeley',\n 'menorah',\n 'mercury',\n 'message',\n 'meta',\n 'meteor',\n 'microblog',\n 'microchip',\n 'microphone',\n 'microphone-alt',\n 'microphone-alt-slash',\n 'microphone-lines',\n 'microphone-lines-slash',\n 'microphone-slash',\n 'microscope',\n 'microsoft',\n 'mill-sign',\n 'minimize',\n 'mintbit',\n 'minus',\n 'minus-circle',\n 'minus-square',\n 'mitten',\n 'mix',\n 'mixcloud',\n 'mixer',\n 'mizuni',\n 'mobile',\n 'mobile-alt',\n 'mobile-android',\n 'mobile-android-alt',\n 'mobile-button',\n 'mobile-phone',\n 'mobile-retro',\n 'mobile-screen',\n 'mobile-screen-button',\n 'mobile-vibrate',\n 'modx',\n 'monero',\n 'money-bill',\n 'money-bill-1',\n 'money-bill-1-wave',\n 'money-bill-alt',\n 'money-bill-transfer',\n 'money-bill-trend-up',\n 'money-bill-wave',\n 'money-bill-wave-alt',\n 'money-bill-wheat',\n 'money-bills',\n 'money-check',\n 'money-check-alt',\n 'money-check-dollar',\n 'monument',\n 'moon',\n 'mortar-board',\n 'mortar-pestle',\n 'mosque',\n 'mosquito',\n 'mosquito-net',\n 'motorcycle',\n 'mound',\n 'mountain',\n 'mountain-city',\n 'mountain-sun',\n 'mouse',\n 'mouse-pointer',\n 'mug-hot',\n 'mug-saucer',\n 'multiply',\n 'museum',\n 'music',\n 'naira-sign',\n 'napster',\n 'navicon',\n 'neos',\n 'network-wired',\n 'neuter',\n 'newspaper',\n 'nextcloud',\n 'nfc-directional',\n 'nfc-symbol',\n 'nimblr',\n 'node',\n 'node-js',\n 'non-binary',\n 'not-equal',\n 'notdef',\n 'note-sticky',\n 'notes-medical',\n 'notion',\n 'npm',\n 'ns8',\n 'nutritionix',\n 'object-group',\n 'object-ungroup',\n 'obs-studio',\n 'obsidian',\n 'octagon',\n 'octopus-deploy',\n 'odnoklassniki',\n 'odnoklassniki-square',\n 'odysee',\n 'oil-can',\n 'oil-well',\n 'old-republic',\n 'om',\n 'openai',\n 'opencart',\n 'openid',\n 'openstreetmap',\n 'opensuse',\n 'opera',\n 'optin-monster',\n 'orcid',\n 'osi',\n 'otter',\n 'outdent',\n 'padlet',\n 'page4',\n 'pagelines',\n 'pager',\n 'paint-brush',\n 'paint-roller',\n 'paintbrush',\n 'palette',\n 'palfed',\n 'pallet',\n 'pandora',\n 'panorama',\n 'paper-plane',\n 'paperclip',\n 'parachute-box',\n 'paragraph',\n 'parking',\n 'passport',\n 'pastafarianism',\n 'paste',\n 'patreon',\n 'pause',\n 'pause-circle',\n 'paw',\n 'paypal',\n 'peace',\n 'pen',\n 'pen-alt',\n 'pen-clip',\n 'pen-fancy',\n 'pen-nib',\n 'pen-ruler',\n 'pen-square',\n 'pen-to-square',\n 'pencil',\n 'pencil-alt',\n 'pencil-ruler',\n 'pencil-square',\n 'pentagon',\n 'people-arrows',\n 'people-arrows-left-right',\n 'people-carry',\n 'people-carry-box',\n 'people-group',\n 'people-line',\n 'people-pulling',\n 'people-robbery',\n 'people-roof',\n 'pepper-hot',\n 'perbyte',\n 'periscope',\n 'person',\n 'person-arrow-down-to-line',\n 'person-arrow-up-from-line',\n 'person-biking',\n 'person-booth',\n 'person-breastfeeding',\n 'person-burst',\n 'person-cane',\n 'person-chalkboard',\n 'person-circle-check',\n 'person-circle-exclamation',\n 'person-circle-minus',\n 'person-circle-plus',\n 'person-circle-question',\n 'person-circle-xmark',\n 'person-digging',\n 'person-dots-from-line',\n 'person-dress',\n 'person-dress-burst',\n 'person-drowning',\n 'person-falling',\n 'person-falling-burst',\n 'person-half-dress',\n 'person-harassing',\n 'person-hiking',\n 'person-military-pointing',\n 'person-military-rifle',\n 'person-military-to-person',\n 'person-praying',\n 'person-pregnant',\n 'person-rays',\n 'person-rifle',\n 'person-running',\n 'person-shelter',\n 'person-skating',\n 'person-skiing',\n 'person-skiing-nordic',\n 'person-snowboarding',\n 'person-swimming',\n 'person-through-window',\n 'person-walking',\n 'person-walking-arrow-loop-left',\n 'person-walking-arrow-right',\n 'person-walking-dashed-line-arrow-right',\n 'person-walking-luggage',\n 'person-walking-with-cane',\n 'peseta-sign',\n 'peso-sign',\n 'phabricator',\n 'phoenix-framework',\n 'phoenix-squadron',\n 'phone',\n 'phone-alt',\n 'phone-flip',\n 'phone-slash',\n 'phone-square',\n 'phone-square-alt',\n 'phone-volume',\n 'photo-film',\n 'photo-video',\n 'php',\n 'picture-in-picture',\n 'pie-chart',\n 'pied-piper',\n 'pied-piper-alt',\n 'pied-piper-hat',\n 'pied-piper-pp',\n 'pied-piper-square',\n 'piggy-bank',\n 'pills',\n 'ping-pong-paddle-ball',\n 'pinterest',\n 'pinterest-p',\n 'pinterest-square',\n 'pisces',\n 'pix',\n 'pixelfed',\n 'pixiv',\n 'pizza-slice',\n 'place-of-worship',\n 'plane',\n 'plane-arrival',\n 'plane-circle-check',\n 'plane-circle-exclamation',\n 'plane-circle-xmark',\n 'plane-departure',\n 'plane-lock',\n 'plane-slash',\n 'plane-up',\n 'plant-wilt',\n 'plate-wheat',\n 'play',\n 'play-circle',\n 'playstation',\n 'plug',\n 'plug-circle-bolt',\n 'plug-circle-check',\n 'plug-circle-exclamation',\n 'plug-circle-minus',\n 'plug-circle-plus',\n 'plug-circle-xmark',\n 'plus-circle',\n 'plus-minus',\n 'plus-square',\n 'podcast',\n 'poll',\n 'poll-h',\n 'poo',\n 'poo-bolt',\n 'poo-storm',\n 'poop',\n 'portrait',\n 'postgresql',\n 'pound-sign',\n 'power-off',\n 'pray',\n 'praying-hands',\n 'prescription',\n 'prescription-bottle',\n 'prescription-bottle-alt',\n 'prescription-bottle-medical',\n 'print',\n 'procedures',\n 'product-hunt',\n 'project-diagram',\n 'pump-medical',\n 'pump-soap',\n 'pushed',\n 'puzzle-piece',\n 'python',\n 'qq',\n 'qrcode',\n 'question-circle',\n 'quidditch',\n 'quidditch-broom-ball',\n 'quinscape',\n 'quora',\n 'quote-left',\n 'quote-left-alt',\n 'quote-right',\n 'quote-right-alt',\n 'quran',\n 'r-project',\n 'radiation',\n 'radiation-alt',\n 'radio',\n 'rainbow',\n 'random',\n 'ranking-star',\n 'raspberry-pi',\n 'ravelry',\n 'react',\n 'reacteurope',\n 'readme',\n 'rebel',\n 'receipt',\n 'record-vinyl',\n 'rectangle-ad',\n 'rectangle-list',\n 'rectangle-times',\n 'rectangle-xmark',\n 'recycle',\n 'red-river',\n 'reddit',\n 'reddit-alien',\n 'reddit-square',\n 'redhat',\n 'redo',\n 'redo-alt',\n 'refresh',\n 'registered',\n 'remove',\n 'remove-format',\n 'rendact',\n 'renren',\n 'reorder',\n 'repeat',\n 'reply',\n 'reply-all',\n 'replyd',\n 'republican',\n 'researchgate',\n 'resolving',\n 'restroom',\n 'retweet',\n 'rev',\n 'ribbon',\n 'right-from-bracket',\n 'right-left',\n 'right-long',\n 'right-to-bracket',\n 'ring',\n 'rmb',\n 'road',\n 'road-barrier',\n 'road-bridge',\n 'road-circle-check',\n 'road-circle-exclamation',\n 'road-circle-xmark',\n 'road-lock',\n 'road-spikes',\n 'roblox-creator-studio',\n 'robot',\n 'rocket',\n 'rocketchat',\n 'rockrms',\n 'rod-asclepius',\n 'rod-snake',\n 'ror',\n 'rotate',\n 'rotate-back',\n 'rotate-backward',\n 'rotate-forward',\n 'rotate-left',\n 'rotate-right',\n 'rouble',\n 'route',\n 'rss',\n 'rss-square',\n 'rub',\n 'ruble',\n 'ruble-sign',\n 'rug',\n 'ruler',\n 'ruler-combined',\n 'ruler-horizontal',\n 'ruler-vertical',\n 'running',\n 'rupee',\n 'rupee-sign',\n 'rupiah-sign',\n 'rust',\n 'sack-dollar',\n 'sack-xmark',\n 'sad-cry',\n 'sad-tear',\n 'safari',\n 'sagittarius',\n 'sailboat',\n 'salesforce',\n 'sass',\n 'satellite',\n 'satellite-dish',\n 'save',\n 'scale-balanced',\n 'scale-unbalanced',\n 'scale-unbalanced-flip',\n 'scaleway',\n 'schlix',\n 'school',\n 'school-circle-check',\n 'school-circle-exclamation',\n 'school-circle-xmark',\n 'school-flag',\n 'school-lock',\n 'scissors',\n 'scorpio',\n 'screenpal',\n 'screwdriver',\n 'screwdriver-wrench',\n 'scribd',\n 'scroll',\n 'scroll-torah',\n 'sd-card',\n 'search',\n 'search-dollar',\n 'search-location',\n 'search-minus',\n 'search-plus',\n 'searchengin',\n 'section',\n 'seedling',\n 'sellcast',\n 'sellsy',\n 'septagon',\n 'server',\n 'servicestack',\n 'shapes',\n 'share',\n 'share-alt',\n 'share-alt-square',\n 'share-from-square',\n 'share-nodes',\n 'share-square',\n 'sheet-plastic',\n 'shekel',\n 'shekel-sign',\n 'sheqel',\n 'sheqel-sign',\n 'shield',\n 'shield-alt',\n 'shield-blank',\n 'shield-cat',\n 'shield-dog',\n 'shield-halved',\n 'shield-heart',\n 'shield-virus',\n 'ship',\n 'shipping-fast',\n 'shirt',\n 'shirtsinbulk',\n 'shoe-prints',\n 'shoelace',\n 'shop',\n 'shop-lock',\n 'shop-slash',\n 'shopify',\n 'shopping-bag',\n 'shopping-basket',\n 'shopping-cart',\n 'shopware',\n 'shower',\n 'shrimp',\n 'shuffle',\n 'shuttle-space',\n 'shuttle-van',\n 'sign',\n 'sign-hanging',\n 'sign-in',\n 'sign-in-alt',\n 'sign-language',\n 'sign-out',\n 'sign-out-alt',\n 'signal',\n 'signal-5',\n 'signal-messenger',\n 'signal-perfect',\n 'signature',\n 'signing',\n 'signs-post',\n 'sim-card',\n 'simplybuilt',\n 'single-quote-left',\n 'single-quote-right',\n 'sink',\n 'sistrix',\n 'sitemap',\n 'sith',\n 'sitrox',\n 'skating',\n 'sketch',\n 'skiing',\n 'skiing-nordic',\n 'skull',\n 'skull-crossbones',\n 'skyatlas',\n 'skype',\n 'slack',\n 'slack-hash',\n 'slash',\n 'sleigh',\n 'sliders',\n 'sliders-h',\n 'slideshare',\n 'smile',\n 'smile-beam',\n 'smile-wink',\n 'smog',\n 'smoking',\n 'smoking-ban',\n 'sms',\n 'snapchat',\n 'snapchat-ghost',\n 'snapchat-square',\n 'snowboarding',\n 'snowflake',\n 'snowman',\n 'snowplow',\n 'soap',\n 'soccer-ball',\n 'socks',\n 'solana',\n 'solar-panel',\n 'sort',\n 'sort-alpha-asc',\n 'sort-alpha-desc',\n 'sort-alpha-down',\n 'sort-alpha-down-alt',\n 'sort-alpha-up',\n 'sort-alpha-up-alt',\n 'sort-amount-asc',\n 'sort-amount-desc',\n 'sort-amount-down',\n 'sort-amount-down-alt',\n 'sort-amount-up',\n 'sort-amount-up-alt',\n 'sort-asc',\n 'sort-desc',\n 'sort-down',\n 'sort-numeric-asc',\n 'sort-numeric-desc',\n 'sort-numeric-down',\n 'sort-numeric-down-alt',\n 'sort-numeric-up',\n 'sort-numeric-up-alt',\n 'sort-up',\n 'soundcloud',\n 'sourcetree',\n 'spa',\n 'space-awesome',\n 'space-shuttle',\n 'spaghetti-monster-flying',\n 'speakap',\n 'speaker-deck',\n 'spell-check',\n 'spider',\n 'spinner',\n 'spiral',\n 'splotch',\n 'spoon',\n 'spotify',\n 'spray-can',\n 'spray-can-sparkles',\n 'sprout',\n 'square',\n 'square-arrow-up-right',\n 'square-behance',\n 'square-binary',\n 'square-bluesky',\n 'square-build-awesome-stroke',\n 'square-caret-down',\n 'square-caret-left',\n 'square-caret-right',\n 'square-caret-up',\n 'square-check',\n 'square-deskpro',\n 'square-dribbble',\n 'square-envelope',\n 'square-facebook',\n 'square-figma',\n 'square-font-awesome',\n 'square-font-awesome-stroke',\n 'square-full',\n 'square-git',\n 'square-github',\n 'square-gitlab',\n 'square-google-plus',\n 'square-h',\n 'square-hacker-news',\n 'square-instagram',\n 'square-js',\n 'square-kickstarter',\n 'square-lastfm',\n 'square-letterboxd',\n 'square-linkedin',\n 'square-minus',\n 'square-nfi',\n 'square-odnoklassniki',\n 'square-parking',\n 'square-pen',\n 'square-person-confined',\n 'square-phone',\n 'square-phone-flip',\n 'square-pied-piper',\n 'square-pinterest',\n 'square-plus',\n 'square-poll-horizontal',\n 'square-poll-vertical',\n 'square-reddit',\n 'square-root-alt',\n 'square-root-variable',\n 'square-rss',\n 'square-share-nodes',\n 'square-snapchat',\n 'square-steam',\n 'square-threads',\n 'square-tumblr',\n 'square-twitter',\n 'square-up-right',\n 'square-upwork',\n 'square-viadeo',\n 'square-vimeo',\n 'square-virus',\n 'square-web-awesome',\n 'square-web-awesome-stroke',\n 'square-whatsapp',\n 'square-x-twitter',\n 'square-xing',\n 'square-xmark',\n 'square-youtube',\n 'squarespace',\n 'stack-exchange',\n 'stack-overflow',\n 'stackpath',\n 'staff-aesculapius',\n 'staff-snake',\n 'stairs',\n 'stamp',\n 'stapler',\n 'star',\n 'star-and-crescent',\n 'star-half',\n 'star-half-alt',\n 'star-half-stroke',\n 'star-of-david',\n 'star-of-life',\n 'staylinked',\n 'steam',\n 'steam-square',\n 'steam-symbol',\n 'step-backward',\n 'step-forward',\n 'sterling-sign',\n 'stethoscope',\n 'sticker-mule',\n 'sticky-note',\n 'stop',\n 'stop-circle',\n 'stopwatch',\n 'stopwatch-20',\n 'store',\n 'store-alt',\n 'store-alt-slash',\n 'store-slash',\n 'storybook',\n 'strava',\n 'stream',\n 'street-view',\n 'strikethrough',\n 'stripe',\n 'stripe-s',\n 'stroopwafel',\n 'stubber',\n 'studiovinari',\n 'stumbleupon',\n 'stumbleupon-circle',\n 'subscript',\n 'substack',\n 'subtract',\n 'subway',\n 'suitcase',\n 'suitcase-medical',\n 'suitcase-rolling',\n 'sun',\n 'sun-plant-wilt',\n 'superpowers',\n 'superscript',\n 'supple',\n 'supportnow',\n 'surprise',\n 'suse',\n 'svelte',\n 'swatchbook',\n 'swift',\n 'swimmer',\n 'swimming-pool',\n 'symfony',\n 'symfonycasts',\n 'synagogue',\n 'sync',\n 'sync-alt',\n 'syringe',\n 't-shirt',\n 'table',\n 'table-cells',\n 'table-cells-column-lock',\n 'table-cells-large',\n 'table-cells-row-lock',\n 'table-cells-row-unlock',\n 'table-columns',\n 'table-list',\n 'table-tennis',\n 'table-tennis-paddle-ball',\n 'tablet',\n 'tablet-alt',\n 'tablet-android',\n 'tablet-button',\n 'tablet-screen-button',\n 'tablets',\n 'tachograph-digital',\n 'tachometer',\n 'tachometer-alt',\n 'tachometer-alt-average',\n 'tachometer-alt-fast',\n 'tachometer-average',\n 'tachometer-fast',\n 'tag',\n 'tags',\n 'tailwind-css',\n 'tanakh',\n 'tape',\n 'tarp',\n 'tarp-droplet',\n 'tasks',\n 'tasks-alt',\n 'taurus',\n 'taxi',\n 'teamspeak',\n 'teeth',\n 'teeth-open',\n 'telegram',\n 'telegram-plane',\n 'teletype',\n 'television',\n 'temperature-0',\n 'temperature-1',\n 'temperature-2',\n 'temperature-3',\n 'temperature-4',\n 'temperature-arrow-down',\n 'temperature-arrow-up',\n 'temperature-down',\n 'temperature-empty',\n 'temperature-full',\n 'temperature-half',\n 'temperature-high',\n 'temperature-low',\n 'temperature-quarter',\n 'temperature-three-quarters',\n 'temperature-up',\n 'tencent-weibo',\n 'tenge',\n 'tenge-sign',\n 'tent',\n 'tent-arrow-down-to-line',\n 'tent-arrow-left-right',\n 'tent-arrow-turn-left',\n 'tent-arrows-down',\n 'tents',\n 'terminal',\n 'tesla',\n 'tex',\n 'text-height',\n 'text-slash',\n 'text-width',\n 'th',\n 'th-large',\n 'th-list',\n 'the-red-yeti',\n 'theater-masks',\n 'themeco',\n 'themeisle',\n 'thermometer',\n 'thermometer-0',\n 'thermometer-1',\n 'thermometer-2',\n 'thermometer-3',\n 'thermometer-4',\n 'thermometer-empty',\n 'thermometer-full',\n 'thermometer-half',\n 'thermometer-quarter',\n 'thermometer-three-quarters',\n 'think-peaks',\n 'threads',\n 'threema',\n 'thumb-tack',\n 'thumb-tack-slash',\n 'thumbs-down',\n 'thumbs-up',\n 'thumbtack',\n 'thumbtack-slash',\n 'thunderstorm',\n 'ticket',\n 'ticket-alt',\n 'ticket-simple',\n 'tidal',\n 'tiktok',\n 'timeline',\n 'times',\n 'times-circle',\n 'times-rectangle',\n 'times-square',\n 'tint',\n 'tint-slash',\n 'tired',\n 'toggle-off',\n 'toggle-on',\n 'toilet',\n 'toilet-paper',\n 'toilet-paper-alt',\n 'toilet-paper-blank',\n 'toilet-paper-slash',\n 'toilet-portable',\n 'toilets-portable',\n 'toolbox',\n 'tools',\n 'tooth',\n 'tor-browser',\n 'torah',\n 'torii-gate',\n 'tornado',\n 'tower-broadcast',\n 'tower-cell',\n 'tower-observation',\n 'tractor',\n 'trade-federation',\n 'trademark',\n 'traffic-light',\n 'trailer',\n 'train',\n 'train-subway',\n 'train-tram',\n 'tram',\n 'transgender',\n 'transgender-alt',\n 'trash',\n 'trash-alt',\n 'trash-arrow-up',\n 'trash-can',\n 'trash-can-arrow-up',\n 'trash-restore',\n 'trash-restore-alt',\n 'tree',\n 'tree-city',\n 'trello',\n 'triangle-circle-square',\n 'triangle-exclamation',\n 'trophy',\n 'trowel',\n 'trowel-bricks',\n 'truck',\n 'truck-arrow-right',\n 'truck-droplet',\n 'truck-fast',\n 'truck-field',\n 'truck-field-un',\n 'truck-front',\n 'truck-loading',\n 'truck-medical',\n 'truck-monster',\n 'truck-moving',\n 'truck-pickup',\n 'truck-plane',\n 'truck-ramp-box',\n 'try',\n 'tshirt',\n 'tty',\n 'tumblr',\n 'tumblr-square',\n 'turkish-lira',\n 'turkish-lira-sign',\n 'turn-down',\n 'turn-up',\n 'tv',\n 'tv-alt',\n 'twitch',\n 'twitter',\n 'twitter-square',\n 'typescript',\n 'typo3',\n 'uber',\n 'ubuntu',\n 'uikit',\n 'ultralytics',\n 'ultralytics-hub',\n 'ultralytics-yolo',\n 'umbraco',\n 'umbrella',\n 'umbrella-beach',\n 'uncharted',\n 'underline',\n 'undo',\n 'undo-alt',\n 'uniregistry',\n 'unison',\n 'unity',\n 'universal-access',\n 'university',\n 'unlink',\n 'unlock',\n 'unlock-alt',\n 'unlock-keyhole',\n 'unreal-engine',\n 'unsorted',\n 'unsplash',\n 'untappd',\n 'up-down',\n 'up-down-left-right',\n 'up-long',\n 'up-right-and-down-left-from-center',\n 'up-right-from-square',\n 'upload',\n 'ups',\n 'upwork',\n 'usb',\n 'user',\n 'user-alt',\n 'user-alt-slash',\n 'user-astronaut',\n 'user-check',\n 'user-circle',\n 'user-clock',\n 'user-cog',\n 'user-doctor',\n 'user-edit',\n 'user-friends',\n 'user-gear',\n 'user-graduate',\n 'user-group',\n 'user-injured',\n 'user-large',\n 'user-large-slash',\n 'user-lock',\n 'user-md',\n 'user-minus',\n 'user-ninja',\n 'user-nurse',\n 'user-pen',\n 'user-plus',\n 'user-secret',\n 'user-shield',\n 'user-slash',\n 'user-tag',\n 'user-tie',\n 'user-times',\n 'user-xmark',\n 'users',\n 'users-between-lines',\n 'users-cog',\n 'users-gear',\n 'users-line',\n 'users-rays',\n 'users-rectangle',\n 'users-slash',\n 'users-viewfinder',\n 'usps',\n 'ussunnah',\n 'utensil-spoon',\n 'utensils',\n 'vaadin',\n 'van-shuttle',\n 'vault',\n 'vcard',\n 'vector-polygon',\n 'venmo',\n 'venmo-v',\n 'venus',\n 'venus-double',\n 'venus-mars',\n 'vest',\n 'vest-patches',\n 'viacoin',\n 'viadeo',\n 'viadeo-square',\n 'vial',\n 'vial-circle-check',\n 'vial-virus',\n 'vials',\n 'viber',\n 'video',\n 'video-camera',\n 'video-slash',\n 'vihara',\n 'vim',\n 'vimeo',\n 'vimeo-square',\n 'vimeo-v',\n 'vine',\n 'virgo',\n 'virus',\n 'virus-covid',\n 'virus-covid-slash',\n 'virus-slash',\n 'viruses',\n 'visual-studio',\n 'vk',\n 'vnv',\n 'voicemail',\n 'volcano',\n 'volleyball',\n 'volleyball-ball',\n 'volume',\n 'volume-control-phone',\n 'volume-down',\n 'volume-high',\n 'volume-low',\n 'volume-medium',\n 'volume-mute',\n 'volume-off',\n 'volume-times',\n 'volume-up',\n 'volume-xmark',\n 'vote-yea',\n 'vr-cardboard',\n 'vsco',\n 'vuejs',\n 'w3c',\n 'walkie-talkie',\n 'walking',\n 'wallet',\n 'wand-magic',\n 'wand-magic-sparkles',\n 'wand-sparkles',\n 'warehouse',\n 'warning',\n 'watchman-monitoring',\n 'water',\n 'water-ladder',\n 'wave-square',\n 'waze',\n 'web-awesome',\n 'webflow',\n 'weebly',\n 'weibo',\n 'weight',\n 'weight-hanging',\n 'weight-scale',\n 'weixin',\n 'whatsapp',\n 'whatsapp-square',\n 'wheat-alt',\n 'wheat-awn',\n 'wheat-awn-circle-exclamation',\n 'wheelchair',\n 'wheelchair-alt',\n 'wheelchair-move',\n 'whiskey-glass',\n 'whmcs',\n 'wifi',\n 'wifi-3',\n 'wifi-strong',\n 'wikipedia-w',\n 'wind',\n 'window-close',\n 'window-maximize',\n 'window-minimize',\n 'window-restore',\n 'windows',\n 'wine-bottle',\n 'wine-glass',\n 'wine-glass-alt',\n 'wine-glass-empty',\n 'wirsindhandwerk',\n 'wix',\n 'wizards-of-the-coast',\n 'wodu',\n 'wolf-pack-battalion',\n 'won',\n 'won-sign',\n 'wordpress',\n 'wordpress-simple',\n 'worm',\n 'wpbeginner',\n 'wpexplorer',\n 'wpforms',\n 'wpressr',\n 'wrench',\n 'wsh',\n 'x-ray',\n 'x-twitter',\n 'xbox',\n 'xing',\n 'xing-square',\n 'xmark',\n 'xmark-circle',\n 'xmark-square',\n 'xmarks-lines',\n 'xmpp',\n 'xrp',\n 'xrpl',\n 'y-combinator',\n 'yahoo',\n 'yammer',\n 'yandex',\n 'yandex-international',\n 'yarn',\n 'yelp',\n 'yen',\n 'yen-sign',\n 'yin-yang',\n 'yoast',\n 'youtube',\n 'youtube-shorts',\n 'youtube-square',\n 'zap',\n 'zhihu',\n 'zoom',\n 'zulip',\n]);\n\n/**\n * Hand-curated Pro-only name → nearest Free alternative, sourced from\n * @ekanos/harness's Pro→Free glyph shim. Not exhaustive — a Pro-only name\n * with no shim entry has no known Free substitute here.\n */\nexport const FA_PRO_TO_FREE_HINTS: ReadonlyMap<string, string> = new Map([\n ['cloud-bolt-sun', 'cloud-bolt'],\n ['cloud-drizzle', 'cloud-rain'],\n ['cloud-fog', 'smog'],\n ['cloud-hail', 'cloud-meatball'],\n ['cloud-hail-mixed', 'cloud-meatball'],\n ['cloud-question', 'circle-question'],\n ['cloud-showers', 'cloud-showers-heavy'],\n ['cloud-snow', 'snowflake'],\n ['clouds', 'cloud'],\n ['clouds-moon', 'cloud-moon'],\n ['clouds-sun', 'cloud-sun'],\n ['fog', 'smog'],\n ['moon-cloud', 'cloud-moon'],\n ['moon-stars', 'moon'],\n ['sparkles', 'wand-magic-sparkles'],\n ['sun-bright', 'sun'],\n ['sun-cloud', 'cloud-sun'],\n]);\n"]}
@@ -0,0 +1,23 @@
1
+ import type { Finding } from '@ekanos/integration-schema';
2
+ /**
3
+ * Flags Font Awesome **Pro**-only `fa-*` icon names in a project's widget
4
+ * source — today this is a silent, runtime-only failure: `@ekanos/ui`'s
5
+ * `Icon` warns once via `console.warn` in dev, but ships nothing to
6
+ * `validate`, so a partner only discovers a Pro-only name when the generated
7
+ * harness (Font Awesome **Free**-only, see `@ekanos/harness`) renders the
8
+ * circle-question fallback in place of the intended glyph — or never
9
+ * discovers it, if nobody was watching the console.
10
+ *
11
+ * `validate` has no live component tree to inspect the way the runtime
12
+ * warning does, and the definition's `component`/`icon` fields are live
13
+ * React values by the time `loadDefinition` resolves them (function
14
+ * references, not paths) — there is no file path to walk back to from an
15
+ * already-imported component. So this scans the project's own `src/**\/*.{ts,tsx}`
16
+ * on disk instead, the same fallback `collectProjectFindings` would use if it
17
+ * needed source text rather than a loaded value.
18
+ *
19
+ * WARN, not error: a Pro-only name is broken UX in a Free-only host, not an
20
+ * unbuildable submission — plenty of Fusion-hosted partners run under Pro,
21
+ * where the exact same name renders correctly.
22
+ */
23
+ export declare function collectIconFindings(projectDir: string): Finding[];
@@ -0,0 +1,120 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { FA_FREE_ICON_NAMES, FA_PRO_TO_FREE_HINTS, } from './generated/fa-free-names.js';
4
+ /**
5
+ * Flags Font Awesome **Pro**-only `fa-*` icon names in a project's widget
6
+ * source — today this is a silent, runtime-only failure: `@ekanos/ui`'s
7
+ * `Icon` warns once via `console.warn` in dev, but ships nothing to
8
+ * `validate`, so a partner only discovers a Pro-only name when the generated
9
+ * harness (Font Awesome **Free**-only, see `@ekanos/harness`) renders the
10
+ * circle-question fallback in place of the intended glyph — or never
11
+ * discovers it, if nobody was watching the console.
12
+ *
13
+ * `validate` has no live component tree to inspect the way the runtime
14
+ * warning does, and the definition's `component`/`icon` fields are live
15
+ * React values by the time `loadDefinition` resolves them (function
16
+ * references, not paths) — there is no file path to walk back to from an
17
+ * already-imported component. So this scans the project's own `src/**\/*.{ts,tsx}`
18
+ * on disk instead, the same fallback `collectProjectFindings` would use if it
19
+ * needed source text rather than a loaded value.
20
+ *
21
+ * WARN, not error: a Pro-only name is broken UX in a Free-only host, not an
22
+ * unbuildable submission — plenty of Fusion-hosted partners run under Pro,
23
+ * where the exact same name renders correctly.
24
+ */
25
+ export function collectIconFindings(projectDir) {
26
+ const srcDir = path.join(projectDir, 'src');
27
+ if (!fs.existsSync(srcDir))
28
+ return [];
29
+ const findings = [];
30
+ for (const file of walkTsFiles(srcDir)) {
31
+ findings.push(...collectIconFindingsInFile(file));
32
+ }
33
+ return findings;
34
+ }
35
+ function* walkTsFiles(dir) {
36
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
37
+ const full = path.join(dir, entry.name);
38
+ if (entry.isDirectory()) {
39
+ yield* walkTsFiles(full);
40
+ }
41
+ else if (/\.(ts|tsx)$/.test(entry.name)) {
42
+ yield full;
43
+ }
44
+ }
45
+ }
46
+ /**
47
+ * One Font Awesome style-family token, e.g. the `fa-solid` in
48
+ * `"fa-solid fa-house"` (the host's icon helper produces exactly this
49
+ * two-token shape). Kept in sync by hand with the host UI package's
50
+ * `FA_ICON_STYLES` — a style name is never itself an icon name, so it must
51
+ * not be treated as one, but that list lives in a browser package this one
52
+ * may not import.
53
+ */
54
+ const FA_STYLE_TOKEN = '(?:solid|regular|light|thin|duotone|sharp|brands|classic)';
55
+ /**
56
+ * A quoted string literal whose ENTIRE contents are a bare `fa-<name>` value
57
+ * or a two-token `fa-<style> fa-<name>` value — anchored to the quote
58
+ * boundaries (the backreference to the opening quote must follow the name
59
+ * pattern immediately) so this cannot match a `fa-`-prefixed SUBSTRING inside
60
+ * a longer, unrelated string.
61
+ *
62
+ * Parameterized on its own backreference number because it is spliced into
63
+ * `FA_ICON_CONTEXT_RE` twice — each copy opens its own capture group, so a
64
+ * hardcoded `\1` in the second copy would wrongly point at the FIRST copy's
65
+ * quote group instead of its own.
66
+ */
67
+ function faIconLiteral(quoteGroup) {
68
+ return `(['"\`])(?:fa-${FA_STYLE_TOKEN}\\s+)?fa-([a-z][a-z0-9]*(?:-[a-z0-9]+)*)\\${quoteGroup}`;
69
+ }
70
+ /**
71
+ * Only literals in a position that plausibly HOLDS an icon name: the `name`/
72
+ * `icon` prop or object key an `<Icon>`, a widget's `category.icon`, or a
73
+ * config object typically uses, or a direct argument to `resolveIcon`/
74
+ * `renderIcon` (`@ekanos/ui`'s runtime helpers).
75
+ *
76
+ * This is a heuristic, not a parser — it will miss an icon name built up any
77
+ * other way (a variable, a template with interpolation, an indirect prop
78
+ * name), and in principle a `name`/`icon` key on some unrelated object could
79
+ * coincidentally hold an `fa-`-shaped string and get flagged. Both failure
80
+ * modes are accepted: a scan that required full TS type information to be
81
+ * exact is not worth the cost here, and this project's own convention names
82
+ * icon props/keys `name` or `icon` specifically to keep that collision rare.
83
+ * Group numbers: 1 = quote, 2 = name for the `name`/`icon` branch; 3 = quote,
84
+ * 4 = name for the `resolveIcon`/`renderIcon` branch.
85
+ */
86
+ const FA_ICON_CONTEXT_RE = new RegExp(`\\b(?:name|icon)\\s*[:=]\\s*\\{?\\s*${faIconLiteral(1)}` +
87
+ `|\\b(?:resolveIcon|renderIcon)\\(\\s*${faIconLiteral(3)}`, 'g');
88
+ function collectIconFindingsInFile(file) {
89
+ var _a;
90
+ const source = fs.readFileSync(file, 'utf8');
91
+ const findings = [];
92
+ const seen = new Set();
93
+ for (const match of source.matchAll(FA_ICON_CONTEXT_RE)) {
94
+ const iconName = (_a = match[2]) !== null && _a !== void 0 ? _a : match[4];
95
+ if (!iconName || FA_FREE_ICON_NAMES.has(iconName))
96
+ continue;
97
+ const dedupeKey = `${iconName}@${match.index}`;
98
+ if (seen.has(dedupeKey))
99
+ continue;
100
+ seen.add(dedupeKey);
101
+ const line = source.slice(0, match.index).split('\n').length;
102
+ const alternative = FA_PRO_TO_FREE_HINTS.get(iconName);
103
+ findings.push({
104
+ check: 'icons/pro-only',
105
+ severity: 'warn',
106
+ file,
107
+ line,
108
+ message: `"fa-${iconName}" is not in the Font Awesome Free set. Fusion itself ` +
109
+ 'loads Font Awesome Pro, so this renders fine there, but the ' +
110
+ 'generated harness (and any other Free-only host) shows the ' +
111
+ 'circle-question placeholder instead of the intended glyph.',
112
+ hint: alternative
113
+ ? `Use "fa-${alternative}" instead — the nearest Free equivalent.`
114
+ : 'Pick a Free icon name — Pro names render as placeholder discs ' +
115
+ 'outside Pro-licensed hosts.',
116
+ });
117
+ }
118
+ return findings;
119
+ }
120
+ //# sourceMappingURL=icon-findings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icon-findings.js","sourceRoot":"","sources":["../src/icon-findings.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Finding } from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport {\n FA_FREE_ICON_NAMES,\n FA_PRO_TO_FREE_HINTS,\n} from './generated/fa-free-names';\n\n/**\n * Flags Font Awesome **Pro**-only `fa-*` icon names in a project's widget\n * source — today this is a silent, runtime-only failure: `@ekanos/ui`'s\n * `Icon` warns once via `console.warn` in dev, but ships nothing to\n * `validate`, so a partner only discovers a Pro-only name when the generated\n * harness (Font Awesome **Free**-only, see `@ekanos/harness`) renders the\n * circle-question fallback in place of the intended glyph — or never\n * discovers it, if nobody was watching the console.\n *\n * `validate` has no live component tree to inspect the way the runtime\n * warning does, and the definition's `component`/`icon` fields are live\n * React values by the time `loadDefinition` resolves them (function\n * references, not paths) — there is no file path to walk back to from an\n * already-imported component. So this scans the project's own `src/**\\/*.{ts,tsx}`\n * on disk instead, the same fallback `collectProjectFindings` would use if it\n * needed source text rather than a loaded value.\n *\n * WARN, not error: a Pro-only name is broken UX in a Free-only host, not an\n * unbuildable submission — plenty of Fusion-hosted partners run under Pro,\n * where the exact same name renders correctly.\n */\nexport function collectIconFindings(projectDir: string): Finding[] {\n const srcDir = path.join(projectDir, 'src');\n if (!fs.existsSync(srcDir)) return [];\n\n const findings: Finding[] = [];\n for (const file of walkTsFiles(srcDir)) {\n findings.push(...collectIconFindingsInFile(file));\n }\n return findings;\n}\n\nfunction* walkTsFiles(dir: string): Generator<string> {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n yield* walkTsFiles(full);\n } else if (/\\.(ts|tsx)$/.test(entry.name)) {\n yield full;\n }\n }\n}\n\n/**\n * One Font Awesome style-family token, e.g. the `fa-solid` in\n * `\"fa-solid fa-house\"` (the host's icon helper produces exactly this\n * two-token shape). Kept in sync by hand with the host UI package's\n * `FA_ICON_STYLES` — a style name is never itself an icon name, so it must\n * not be treated as one, but that list lives in a browser package this one\n * may not import.\n */\nconst FA_STYLE_TOKEN =\n '(?:solid|regular|light|thin|duotone|sharp|brands|classic)';\n\n/**\n * A quoted string literal whose ENTIRE contents are a bare `fa-<name>` value\n * or a two-token `fa-<style> fa-<name>` value — anchored to the quote\n * boundaries (the backreference to the opening quote must follow the name\n * pattern immediately) so this cannot match a `fa-`-prefixed SUBSTRING inside\n * a longer, unrelated string.\n *\n * Parameterized on its own backreference number because it is spliced into\n * `FA_ICON_CONTEXT_RE` twice — each copy opens its own capture group, so a\n * hardcoded `\\1` in the second copy would wrongly point at the FIRST copy's\n * quote group instead of its own.\n */\nfunction faIconLiteral(quoteGroup: number): string {\n return `(['\"\\`])(?:fa-${FA_STYLE_TOKEN}\\\\s+)?fa-([a-z][a-z0-9]*(?:-[a-z0-9]+)*)\\\\${quoteGroup}`;\n}\n\n/**\n * Only literals in a position that plausibly HOLDS an icon name: the `name`/\n * `icon` prop or object key an `<Icon>`, a widget's `category.icon`, or a\n * config object typically uses, or a direct argument to `resolveIcon`/\n * `renderIcon` (`@ekanos/ui`'s runtime helpers).\n *\n * This is a heuristic, not a parser — it will miss an icon name built up any\n * other way (a variable, a template with interpolation, an indirect prop\n * name), and in principle a `name`/`icon` key on some unrelated object could\n * coincidentally hold an `fa-`-shaped string and get flagged. Both failure\n * modes are accepted: a scan that required full TS type information to be\n * exact is not worth the cost here, and this project's own convention names\n * icon props/keys `name` or `icon` specifically to keep that collision rare.\n * Group numbers: 1 = quote, 2 = name for the `name`/`icon` branch; 3 = quote,\n * 4 = name for the `resolveIcon`/`renderIcon` branch.\n */\nconst FA_ICON_CONTEXT_RE = new RegExp(\n `\\\\b(?:name|icon)\\\\s*[:=]\\\\s*\\\\{?\\\\s*${faIconLiteral(1)}` +\n `|\\\\b(?:resolveIcon|renderIcon)\\\\(\\\\s*${faIconLiteral(3)}`,\n 'g',\n);\n\nfunction collectIconFindingsInFile(file: string): Finding[] {\n const source = fs.readFileSync(file, 'utf8');\n const findings: Finding[] = [];\n const seen = new Set<string>();\n\n for (const match of source.matchAll(FA_ICON_CONTEXT_RE)) {\n const iconName = match[2] ?? match[4];\n if (!iconName || FA_FREE_ICON_NAMES.has(iconName)) continue;\n\n const dedupeKey = `${iconName}@${match.index}`;\n if (seen.has(dedupeKey)) continue;\n seen.add(dedupeKey);\n\n const line = source.slice(0, match.index).split('\\n').length;\n const alternative = FA_PRO_TO_FREE_HINTS.get(iconName);\n\n findings.push({\n check: 'icons/pro-only',\n severity: 'warn',\n file,\n line,\n message:\n `\"fa-${iconName}\" is not in the Font Awesome Free set. Fusion itself ` +\n 'loads Font Awesome Pro, so this renders fine there, but the ' +\n 'generated harness (and any other Free-only host) shows the ' +\n 'circle-question placeholder instead of the intended glyph.',\n hint: alternative\n ? `Use \"fa-${alternative}\" instead — the nearest Free equivalent.`\n : 'Pick a Free icon name — Pro names render as placeholder discs ' +\n 'outside Pro-licensed hosts.',\n });\n }\n\n return findings;\n}\n"]}
package/dist/pack.js CHANGED
@@ -2,6 +2,7 @@ import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
3
  import * as zlib from 'node:zlib';
4
4
  import { preconditionError, validationError } from './errors.js';
5
+ import { VITEST_CONFIG_NAMES } from './project-checks.js';
5
6
  /**
6
7
  * Deterministic project packing for `ekanos publish`.
7
8
  *
@@ -13,8 +14,20 @@ import { preconditionError, validationError } from './errors.js';
13
14
  *
14
15
  * - `ekanos.json`, `package.json` (required)
15
16
  * - `README.md` (when present)
17
+ * - `tsconfig*.json` at the project root (when present)
18
+ * - a vitest/vite config at the project root (when present — see
19
+ * `VITEST_CONFIG_NAMES`)
16
20
  * - everything under `src/`, recursively
17
21
  *
22
+ * The tsconfig/vitest entries exist because the hosted gate's
23
+ * `checks/typecheck` and `checks/tests` stages run the project's OWN `tsc`
24
+ * and `vitest` — over the ARCHIVE, not the partner's working directory — so
25
+ * without them there is no `tsconfig.json` to compile against (`tsc --noEmit`
26
+ * falls back to printing its help text and exiting 1, not a type error) and
27
+ * no test config to load the SDK's server-inline block. `ekanos init`
28
+ * scaffolds both at the project root, so a project published straight from
29
+ * `init` always has them; this walk just stops silently dropping them.
30
+ *
18
31
  * Excluded everywhere: dotfiles and dot-directories (which covers `.ekanos`,
19
32
  * `.git`, `.env`), `node_modules`, and anything that is not a regular file
20
33
  * (symlinks are skipped, not followed — a link pointing outside the project
@@ -70,6 +83,7 @@ export function selectProjectFiles(projectDir) {
70
83
  if (isRegularFile(path.join(projectDir, 'README.md'))) {
71
84
  selected.push('README.md');
72
85
  }
86
+ selected.push(...selectRootConfigFiles(projectDir));
73
87
  const srcDir = path.join(projectDir, 'src');
74
88
  // lstat, not stat: `src` itself as a symlink must not pull a foreign tree
75
89
  // into the archive — the same rule walk() applies to every entry inside.
@@ -78,6 +92,35 @@ export function selectProjectFiles(projectDir) {
78
92
  }
79
93
  return selected.sort();
80
94
  }
95
+ /** `tsconfig.json`, plus any sibling a root `tsconfig.json` might `extends`
96
+ * (e.g. `tsconfig.build.json`) — matched by name, not content, since packing
97
+ * runs before anything parses JSON with comments. Root-level only: this is
98
+ * about the build/test config the gate's own stages need, not a recursive
99
+ * search. */
100
+ const TSCONFIG_PATTERN = /^tsconfig(\.[^./]+)?\.json$/;
101
+ /**
102
+ * The project-root config files the hosted gate's `checks/typecheck` and
103
+ * `checks/tests` stages need to run the project's OWN `tsc`/`vitest`
104
+ * meaningfully — see the module doc comment above. Each is included only
105
+ * when present as a regular file (never a symlink, matching every other
106
+ * entry point in this walk), so a project without one of these (unusual, but
107
+ * not invalid) packs exactly as before.
108
+ */
109
+ function selectRootConfigFiles(projectDir) {
110
+ const selected = [];
111
+ for (const entry of fs.readdirSync(projectDir, { withFileTypes: true })) {
112
+ if (!TSCONFIG_PATTERN.test(entry.name))
113
+ continue;
114
+ if (!isRegularFile(path.join(projectDir, entry.name)))
115
+ continue;
116
+ selected.push(entry.name);
117
+ }
118
+ for (const name of VITEST_CONFIG_NAMES) {
119
+ if (isRegularFile(path.join(projectDir, name)))
120
+ selected.push(name);
121
+ }
122
+ return selected;
123
+ }
81
124
  function walk(projectDir, relativeDir) {
82
125
  const absoluteDir = path.join(projectDir, relativeDir);
83
126
  const collected = [];
package/dist/pack.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"pack.js","sourceRoot":"","sources":["../src/pack.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,UAAU,GAAG,GAAG,CAAC;AAEvB,+EAA+E;AAC/E,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAE9B,2EAA2E;AAC3E,2EAA2E;AAC3E,6EAA6E;AAC7E,wCAAwC;AACxC,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AASjD,MAAM,UAAU,WAAW,CAAC,UAAkB;IAC5C,MAAM,KAAK,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAE7C,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QAE1C,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;QACjD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAErB,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,UAAU,CAAC;QAC9C,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;YACpB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAED,mCAAmC;IACnC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC;IAE1C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IAEnE,IAAI,OAAO,CAAC,MAAM,GAAG,iBAAiB,EAAE,CAAC;QACvC,MAAM,eAAe,CACnB,yBAAyB,OAAO,CAAC,MAAM,mBAAmB;YACxD,GAAG,iBAAiB,yBAAyB,EAC/C,iEAAiE;YAC/D,sCAAsC,CACzC,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC5B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,UAAkB;IACnD,KAAK,MAAM,QAAQ,IAAI,CAAC,aAAa,EAAE,cAAc,CAAC,EAAE,CAAC;QACvD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;YACpD,MAAM,iBAAiB,CACrB,eAAe,UAAU,KAAK,QAAQ,cAAc,EACpD,oEAAoE;gBAClE,uDAAuD,CAC1D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;IAEjD,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC;QACtD,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC7B,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAC5C,0EAA0E;IAC1E,yEAAyE;IACzE,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QAChE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC;AAED,SAAS,IAAI,CAAC,UAAkB,EAAE,WAAmB;IACnD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IACvD,MAAM,SAAS,GAAa,EAAE,CAAC;IAE/B,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,WAAW,CAAC,WAAW,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACzE,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QACzC,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc;YAAE,SAAS;QAE5C,MAAM,QAAQ,GAAG,GAAG,WAAW,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QAEhD,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC9C,SAAS;QACX,CAAC;QAED,6DAA6D;QAC7D,qEAAqE;QACrE,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACnB,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,aAAa,CAAC,QAAgB;IACrC,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC;IACzC,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,SAAS,CAAC,YAAoB,EAAE,IAAY;IACnD,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,cAAc,CAAC,YAAY,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAExC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IACnC,UAAU,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO;IAC1C,UAAU,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM;IACrC,UAAU,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM;IACrC,UAAU,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;IAClC,UAAU,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,mBAAmB,CAAC,CAAC;IACjD,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,qCAAqC;IACjE,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,yBAAyB;IAC5D,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;IACtC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,UAAU;IAC9C,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IAEvC,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,KAAK,MAAM,IAAI,IAAI,MAAM;QAAE,QAAQ,IAAI,IAAI,CAAC;IAE5C,mEAAmE;IACnE,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;IAE9E,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,cAAc,CAAC,YAAoB;IAI1C,IAAI,MAAM,CAAC,UAAU,CAAC,YAAY,EAAE,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;QACnD,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAC5C,CAAC;IAED,kEAAkE;IAClE,KAAK,IAAI,CAAC,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACjD,IAAI,YAAY,CAAC,CAAC,CAAC,KAAK,GAAG;YAAE,SAAS;QAEtC,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAEvC,IACE,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG;YACtC,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,GAAG,EACxC,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,MAAM,eAAe,CACnB,gBAAgB,YAAY,0CAA0C,EACtE,qEAAqE;QACnE,2BAA2B,CAC9B,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CACjB,MAAc,EACd,MAAc,EACd,MAAc,EACd,KAAa;IAEb,MAAM,CAAC,KAAK,CACV,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,GAAG,CAAC,IAAI,EAClD,MAAM,EACN,MAAM,EACN,QAAQ,CACT,CAAC;AACJ,CAAC","sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as zlib from 'node:zlib';\n\nimport { preconditionError, validationError } from './errors';\n\n/**\n * Deterministic project packing for `ekanos publish`.\n *\n * A minimal ustar writer over Node's built-ins — no `tar` dependency. The\n * selection is deliberately a WHITELIST, not \"everything minus a blocklist\":\n * the submission is reviewed by an operator and installed into Fusion, so the\n * archive must contain exactly the files the toolchain knows about and\n * nothing a working directory happens to hold.\n *\n * - `ekanos.json`, `package.json` (required)\n * - `README.md` (when present)\n * - everything under `src/`, recursively\n *\n * Excluded everywhere: dotfiles and dot-directories (which covers `.ekanos`,\n * `.git`, `.env`), `node_modules`, and anything that is not a regular file\n * (symlinks are skipped, not followed — a link pointing outside the project\n * must never pull foreign bytes into a submission).\n *\n * Determinism: entries are sorted by path and every header carries a fixed\n * mtime, so packing the same tree twice yields byte-identical archives and a\n * stable sha256.\n */\n\nconst BLOCK_SIZE = 512;\n\n/** Fixed header mtime — determinism over provenance (the VCS owns history). */\nconst FIXED_MTIME_SECONDS = 0;\n\n/** The server refuses archives over 5 MiB; fail fast on the client too. */\n// 4 MiB — mirrors the server route's cap, which itself sits under Vercel's\n// ~4.5 MB request-body ceiling so oversize is caught here with a clear error\n// instead of by an opaque platform 413.\nexport const MAX_ARCHIVE_BYTES = 4 * 1024 * 1024;\n\nexport interface PackedProject {\n /** The gzipped tarball. */\n archive: Buffer;\n /** Project-relative POSIX paths, in the order they were packed. */\n files: string[];\n}\n\nexport function packProject(projectDir: string): PackedProject {\n const files = selectProjectFiles(projectDir);\n\n const blocks: Buffer[] = [];\n\n for (const relative of files) {\n const absolute = path.join(projectDir, relative);\n const content = fs.readFileSync(absolute);\n\n blocks.push(tarHeader(relative, content.length));\n blocks.push(content);\n\n const remainder = content.length % BLOCK_SIZE;\n if (remainder !== 0) {\n blocks.push(Buffer.alloc(BLOCK_SIZE - remainder));\n }\n }\n\n // End-of-archive: two zero blocks.\n blocks.push(Buffer.alloc(BLOCK_SIZE * 2));\n\n const archive = zlib.gzipSync(Buffer.concat(blocks), { level: 9 });\n\n if (archive.length > MAX_ARCHIVE_BYTES) {\n throw validationError(\n `The packed archive is ${archive.length} bytes, over the ` +\n `${MAX_ARCHIVE_BYTES}-byte submission limit.`,\n 'Reduce the project to source only — large binary assets do not ' +\n 'belong in an integration submission.',\n );\n }\n\n return { archive, files };\n}\n\n/**\n * The whitelist walk. Exported for tests: the selection rules are the part\n * with security consequences, so they are asserted directly.\n */\nexport function selectProjectFiles(projectDir: string): string[] {\n for (const required of ['ekanos.json', 'package.json']) {\n if (!isRegularFile(path.join(projectDir, required))) {\n throw preconditionError(\n `Cannot pack ${projectDir}: ${required} is missing.`,\n `Run \"ekanos publish\" from an integration project (or pass --dir), ` +\n `and run \"ekanos init\" first if this is a new project.`,\n );\n }\n }\n\n const selected = ['ekanos.json', 'package.json'];\n\n if (isRegularFile(path.join(projectDir, 'README.md'))) {\n selected.push('README.md');\n }\n\n const srcDir = path.join(projectDir, 'src');\n // lstat, not stat: `src` itself as a symlink must not pull a foreign tree\n // into the archive — the same rule walk() applies to every entry inside.\n if (fs.existsSync(srcDir) && fs.lstatSync(srcDir).isDirectory()) {\n selected.push(...walk(projectDir, 'src'));\n }\n\n return selected.sort();\n}\n\nfunction walk(projectDir: string, relativeDir: string): string[] {\n const absoluteDir = path.join(projectDir, relativeDir);\n const collected: string[] = [];\n\n for (const entry of fs.readdirSync(absoluteDir, { withFileTypes: true })) {\n if (entry.name.startsWith('.')) continue;\n if (entry.name === 'node_modules') continue;\n\n const relative = `${relativeDir}/${entry.name}`;\n\n if (entry.isDirectory()) {\n collected.push(...walk(projectDir, relative));\n continue;\n }\n\n // Regular files only. `isFile()` is false for symlinks under\n // `withFileTypes`, so a link — wherever it points — is skipped here.\n if (entry.isFile()) {\n collected.push(relative);\n }\n }\n\n return collected;\n}\n\nfunction isRegularFile(absolute: string): boolean {\n try {\n return fs.lstatSync(absolute).isFile();\n } catch {\n return false;\n }\n}\n\n/**\n * One 512-byte ustar header. Long paths use the ustar `prefix` field\n * (155 + '/' + 100); a path that fits neither is refused with a clear error\n * rather than silently truncated.\n */\nfunction tarHeader(relativePath: string, size: number): Buffer {\n const { name, prefix } = splitUstarPath(relativePath);\n const header = Buffer.alloc(BLOCK_SIZE);\n\n header.write(name, 0, 100, 'utf8');\n writeOctal(header, 100, 8, 0o644); // mode\n writeOctal(header, 108, 8, 0); // uid\n writeOctal(header, 116, 8, 0); // gid\n writeOctal(header, 124, 12, size);\n writeOctal(header, 136, 12, FIXED_MTIME_SECONDS);\n header.fill(' ', 148, 156); // checksum placeholder: eight spaces\n header.write('0', 156, 1, 'utf8'); // typeflag: regular file\n header.write('ustar', 257, 5, 'utf8');\n header.write('00', 263, 2, 'utf8'); // version\n header.write(prefix, 345, 155, 'utf8');\n\n let checksum = 0;\n for (const byte of header) checksum += byte;\n\n // Six octal digits, NUL, space — the historical checksum encoding.\n header.write(`${checksum.toString(8).padStart(6, '0')}\\0 `, 148, 8, 'latin1');\n\n return header;\n}\n\nfunction splitUstarPath(relativePath: string): {\n name: string;\n prefix: string;\n} {\n if (Buffer.byteLength(relativePath, 'utf8') <= 100) {\n return { name: relativePath, prefix: '' };\n }\n\n // Split at a '/' so that name ≤ 100 bytes and prefix ≤ 155 bytes.\n for (let i = relativePath.length - 1; i > 0; i--) {\n if (relativePath[i] !== '/') continue;\n\n const prefix = relativePath.slice(0, i);\n const name = relativePath.slice(i + 1);\n\n if (\n Buffer.byteLength(name, 'utf8') <= 100 &&\n Buffer.byteLength(prefix, 'utf8') <= 155\n ) {\n return { name, prefix };\n }\n }\n\n throw validationError(\n `Cannot pack \"${relativePath}\": the path is too long for a tar entry.`,\n 'Shorten the file path (tar limits one segment to 100 bytes and the ' +\n 'directory prefix to 155).',\n );\n}\n\nfunction writeOctal(\n header: Buffer,\n offset: number,\n length: number,\n value: number,\n): void {\n header.write(\n `${value.toString(8).padStart(length - 1, '0')}\\0`,\n offset,\n length,\n 'latin1',\n );\n}\n"]}
1
+ {"version":3,"file":"pack.js","sourceRoot":"","sources":["../src/pack.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as zlib from 'node:zlib';\n\nimport { preconditionError, validationError } from './errors';\nimport { VITEST_CONFIG_NAMES } from './project-checks';\n\n/**\n * Deterministic project packing for `ekanos publish`.\n *\n * A minimal ustar writer over Node's built-ins — no `tar` dependency. The\n * selection is deliberately a WHITELIST, not \"everything minus a blocklist\":\n * the submission is reviewed by an operator and installed into Fusion, so the\n * archive must contain exactly the files the toolchain knows about and\n * nothing a working directory happens to hold.\n *\n * - `ekanos.json`, `package.json` (required)\n * - `README.md` (when present)\n * - `tsconfig*.json` at the project root (when present)\n * - a vitest/vite config at the project root (when present — see\n * `VITEST_CONFIG_NAMES`)\n * - everything under `src/`, recursively\n *\n * The tsconfig/vitest entries exist because the hosted gate's\n * `checks/typecheck` and `checks/tests` stages run the project's OWN `tsc`\n * and `vitest` — over the ARCHIVE, not the partner's working directory — so\n * without them there is no `tsconfig.json` to compile against (`tsc --noEmit`\n * falls back to printing its help text and exiting 1, not a type error) and\n * no test config to load the SDK's server-inline block. `ekanos init`\n * scaffolds both at the project root, so a project published straight from\n * `init` always has them; this walk just stops silently dropping them.\n *\n * Excluded everywhere: dotfiles and dot-directories (which covers `.ekanos`,\n * `.git`, `.env`), `node_modules`, and anything that is not a regular file\n * (symlinks are skipped, not followed — a link pointing outside the project\n * must never pull foreign bytes into a submission).\n *\n * Determinism: entries are sorted by path and every header carries a fixed\n * mtime, so packing the same tree twice yields byte-identical archives and a\n * stable sha256.\n */\n\nconst BLOCK_SIZE = 512;\n\n/** Fixed header mtime — determinism over provenance (the VCS owns history). */\nconst FIXED_MTIME_SECONDS = 0;\n\n/** The server refuses archives over 5 MiB; fail fast on the client too. */\n// 4 MiB — mirrors the server route's cap, which itself sits under Vercel's\n// ~4.5 MB request-body ceiling so oversize is caught here with a clear error\n// instead of by an opaque platform 413.\nexport const MAX_ARCHIVE_BYTES = 4 * 1024 * 1024;\n\nexport interface PackedProject {\n /** The gzipped tarball. */\n archive: Buffer;\n /** Project-relative POSIX paths, in the order they were packed. */\n files: string[];\n}\n\nexport function packProject(projectDir: string): PackedProject {\n const files = selectProjectFiles(projectDir);\n\n const blocks: Buffer[] = [];\n\n for (const relative of files) {\n const absolute = path.join(projectDir, relative);\n const content = fs.readFileSync(absolute);\n\n blocks.push(tarHeader(relative, content.length));\n blocks.push(content);\n\n const remainder = content.length % BLOCK_SIZE;\n if (remainder !== 0) {\n blocks.push(Buffer.alloc(BLOCK_SIZE - remainder));\n }\n }\n\n // End-of-archive: two zero blocks.\n blocks.push(Buffer.alloc(BLOCK_SIZE * 2));\n\n const archive = zlib.gzipSync(Buffer.concat(blocks), { level: 9 });\n\n if (archive.length > MAX_ARCHIVE_BYTES) {\n throw validationError(\n `The packed archive is ${archive.length} bytes, over the ` +\n `${MAX_ARCHIVE_BYTES}-byte submission limit.`,\n 'Reduce the project to source only — large binary assets do not ' +\n 'belong in an integration submission.',\n );\n }\n\n return { archive, files };\n}\n\n/**\n * The whitelist walk. Exported for tests: the selection rules are the part\n * with security consequences, so they are asserted directly.\n */\nexport function selectProjectFiles(projectDir: string): string[] {\n for (const required of ['ekanos.json', 'package.json']) {\n if (!isRegularFile(path.join(projectDir, required))) {\n throw preconditionError(\n `Cannot pack ${projectDir}: ${required} is missing.`,\n `Run \"ekanos publish\" from an integration project (or pass --dir), ` +\n `and run \"ekanos init\" first if this is a new project.`,\n );\n }\n }\n\n const selected = ['ekanos.json', 'package.json'];\n\n if (isRegularFile(path.join(projectDir, 'README.md'))) {\n selected.push('README.md');\n }\n\n selected.push(...selectRootConfigFiles(projectDir));\n\n const srcDir = path.join(projectDir, 'src');\n // lstat, not stat: `src` itself as a symlink must not pull a foreign tree\n // into the archive — the same rule walk() applies to every entry inside.\n if (fs.existsSync(srcDir) && fs.lstatSync(srcDir).isDirectory()) {\n selected.push(...walk(projectDir, 'src'));\n }\n\n return selected.sort();\n}\n\n/** `tsconfig.json`, plus any sibling a root `tsconfig.json` might `extends`\n * (e.g. `tsconfig.build.json`) — matched by name, not content, since packing\n * runs before anything parses JSON with comments. Root-level only: this is\n * about the build/test config the gate's own stages need, not a recursive\n * search. */\nconst TSCONFIG_PATTERN = /^tsconfig(\\.[^./]+)?\\.json$/;\n\n/**\n * The project-root config files the hosted gate's `checks/typecheck` and\n * `checks/tests` stages need to run the project's OWN `tsc`/`vitest`\n * meaningfully — see the module doc comment above. Each is included only\n * when present as a regular file (never a symlink, matching every other\n * entry point in this walk), so a project without one of these (unusual, but\n * not invalid) packs exactly as before.\n */\nfunction selectRootConfigFiles(projectDir: string): string[] {\n const selected: string[] = [];\n\n for (const entry of fs.readdirSync(projectDir, { withFileTypes: true })) {\n if (!TSCONFIG_PATTERN.test(entry.name)) continue;\n if (!isRegularFile(path.join(projectDir, entry.name))) continue;\n selected.push(entry.name);\n }\n\n for (const name of VITEST_CONFIG_NAMES) {\n if (isRegularFile(path.join(projectDir, name))) selected.push(name);\n }\n\n return selected;\n}\n\nfunction walk(projectDir: string, relativeDir: string): string[] {\n const absoluteDir = path.join(projectDir, relativeDir);\n const collected: string[] = [];\n\n for (const entry of fs.readdirSync(absoluteDir, { withFileTypes: true })) {\n if (entry.name.startsWith('.')) continue;\n if (entry.name === 'node_modules') continue;\n\n const relative = `${relativeDir}/${entry.name}`;\n\n if (entry.isDirectory()) {\n collected.push(...walk(projectDir, relative));\n continue;\n }\n\n // Regular files only. `isFile()` is false for symlinks under\n // `withFileTypes`, so a link — wherever it points — is skipped here.\n if (entry.isFile()) {\n collected.push(relative);\n }\n }\n\n return collected;\n}\n\nfunction isRegularFile(absolute: string): boolean {\n try {\n return fs.lstatSync(absolute).isFile();\n } catch {\n return false;\n }\n}\n\n/**\n * One 512-byte ustar header. Long paths use the ustar `prefix` field\n * (155 + '/' + 100); a path that fits neither is refused with a clear error\n * rather than silently truncated.\n */\nfunction tarHeader(relativePath: string, size: number): Buffer {\n const { name, prefix } = splitUstarPath(relativePath);\n const header = Buffer.alloc(BLOCK_SIZE);\n\n header.write(name, 0, 100, 'utf8');\n writeOctal(header, 100, 8, 0o644); // mode\n writeOctal(header, 108, 8, 0); // uid\n writeOctal(header, 116, 8, 0); // gid\n writeOctal(header, 124, 12, size);\n writeOctal(header, 136, 12, FIXED_MTIME_SECONDS);\n header.fill(' ', 148, 156); // checksum placeholder: eight spaces\n header.write('0', 156, 1, 'utf8'); // typeflag: regular file\n header.write('ustar', 257, 5, 'utf8');\n header.write('00', 263, 2, 'utf8'); // version\n header.write(prefix, 345, 155, 'utf8');\n\n let checksum = 0;\n for (const byte of header) checksum += byte;\n\n // Six octal digits, NUL, space — the historical checksum encoding.\n header.write(`${checksum.toString(8).padStart(6, '0')}\\0 `, 148, 8, 'latin1');\n\n return header;\n}\n\nfunction splitUstarPath(relativePath: string): {\n name: string;\n prefix: string;\n} {\n if (Buffer.byteLength(relativePath, 'utf8') <= 100) {\n return { name: relativePath, prefix: '' };\n }\n\n // Split at a '/' so that name ≤ 100 bytes and prefix ≤ 155 bytes.\n for (let i = relativePath.length - 1; i > 0; i--) {\n if (relativePath[i] !== '/') continue;\n\n const prefix = relativePath.slice(0, i);\n const name = relativePath.slice(i + 1);\n\n if (\n Buffer.byteLength(name, 'utf8') <= 100 &&\n Buffer.byteLength(prefix, 'utf8') <= 155\n ) {\n return { name, prefix };\n }\n }\n\n throw validationError(\n `Cannot pack \"${relativePath}\": the path is too long for a tar entry.`,\n 'Shorten the file path (tar limits one segment to 100 bytes and the ' +\n 'directory prefix to 155).',\n );\n}\n\nfunction writeOctal(\n header: Buffer,\n offset: number,\n length: number,\n value: number,\n): void {\n header.write(\n `${value.toString(8).padStart(length - 1, '0')}\\0`,\n offset,\n length,\n 'latin1',\n );\n}\n"]}
@@ -1,5 +1,12 @@
1
1
  import type { Finding } from '@ekanos/integration-schema';
2
2
  import { type EkanosProject } from './project.js';
3
+ /**
4
+ * Every vitest/vite config basename `ekanos init` might have scaffolded (or a
5
+ * partner might have renamed to). Exported so `pack.ts` can pack exactly the
6
+ * same set it checks here — one list, so packing and validating this project
7
+ * property can never disagree on what "the test config" even is.
8
+ */
9
+ export declare const VITEST_CONFIG_NAMES: string[];
3
10
  /**
4
11
  * Project-level integrity checks that read files in the project root (next to
5
12
  * ekanos.json), NOT the integration definition. These are deliberately kept
@@ -1,7 +1,13 @@
1
1
  import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
3
  import { isDocUrl } from './project.js';
4
- const VITEST_CONFIG_NAMES = [
4
+ /**
5
+ * Every vitest/vite config basename `ekanos init` might have scaffolded (or a
6
+ * partner might have renamed to). Exported so `pack.ts` can pack exactly the
7
+ * same set it checks here — one list, so packing and validating this project
8
+ * property can never disagree on what "the test config" even is.
9
+ */
10
+ export const VITEST_CONFIG_NAMES = [
5
11
  'vitest.config.ts',
6
12
  'vitest.config.mts',
7
13
  'vitest.config.cts',
@@ -1 +1 @@
1
- {"version":3,"file":"project-checks.js","sourceRoot":"","sources":["../src/project-checks.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Finding } from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport { type EkanosProject, isDocUrl } from './project';\n\nconst VITEST_CONFIG_NAMES = [\n 'vitest.config.ts',\n 'vitest.config.mts',\n 'vitest.config.cts',\n 'vitest.config.js',\n 'vitest.config.mjs',\n 'vitest.config.cjs',\n 'vite.config.ts',\n 'vite.config.mts',\n 'vite.config.js',\n 'vite.config.mjs',\n];\n\n/** The exact block the hint quotes — the one config that makes the SDK load. */\nconst REQUIRED_INLINE_BLOCK = [\n 'test: {',\n ' server: {',\n ' deps: {',\n \" inline: ['@ekanos/sdk'],\",\n ' },',\n ' },',\n '}',\n].join('\\n');\n\n/**\n * Project-level integrity checks that read files in the project root (next to\n * ekanos.json), NOT the integration definition. These are deliberately kept\n * out of the schema package's definition collectors: the definition is valid or\n * not on its own; whether the partner's TEST runner is configured to load the\n * published SDK is a property of THIS project.\n *\n * The highest-value check: a partner's vitest must inline `@ekanos/sdk`. The\n * published SDK dist imports extensionless `next/link`, so without\n * `test.server.deps.inline: ['@ekanos/sdk']` vitest fails to load the SDK, the\n * test file silently imports nothing, and vitest reports green over zero tests.\n *\n * The check is conditional: if the project declares NO vitest/vite config at\n * all, there is nothing to assert (the `test` verb would surface a missing\n * runner on its own). If a config IS present, it MUST inline the SDK.\n */\nexport function collectProjectFindings(projectDir: string): Finding[] {\n const configFile = VITEST_CONFIG_NAMES.map((name) =>\n path.join(projectDir, name),\n ).find((candidate) => fs.existsSync(candidate));\n\n if (!configFile) return [];\n\n const source = fs.readFileSync(configFile, 'utf8');\n if (vitestInlinesSdk(source)) return [];\n\n return [\n {\n check: 'project.vitest-inline-sdk',\n severity: 'error',\n file: configFile,\n message:\n `${path.basename(configFile)} does not inline @ekanos/sdk. The ` +\n `published SDK dist imports extensionless \"next/link\", so without ` +\n `test.server.deps.inline including \"@ekanos/sdk\", vitest cannot load ` +\n `the SDK — the test file imports nothing and vitest reports green ` +\n `over zero tests.`,\n hint:\n `Add this to your vitest config's defineConfig so the SDK is ` +\n `transformed for the test runner:\\n\\n${REQUIRED_INLINE_BLOCK}`,\n },\n ];\n}\n\n/**\n * Advisory check on the `docs` array: a relative entry that resolves to\n * nothing on disk gets a WARNING — never an error, because a missing doc file\n * must not block a publish (the gate refuses only error-severity findings).\n * URLs are never checked: `validate` does no network, ever, and an agent\n * dereferences them at authoring time instead.\n */\nexport function collectDocsFindings(\n project: EkanosProject,\n projectDir: string,\n): Finding[] {\n const findings: Finding[] = [];\n\n for (const entry of project.docs ?? []) {\n if (isDocUrl(entry)) continue;\n\n const resolved = path.resolve(projectDir, entry);\n if (fs.existsSync(resolved)) continue;\n\n findings.push({\n check: 'docs/missing-file',\n severity: 'warn',\n file: resolved,\n message:\n `ekanos.json lists \"${entry}\" under \"docs\", but no file exists ` +\n `there (resolved to ${resolved}).`,\n hint:\n `Create ${entry}, or fix the path in ekanos.json's \"docs\" array so ` +\n 'it points at real API documentation.',\n });\n }\n\n return findings;\n}\n\n/**\n * True when the config source contains an `inline: [ … ]` array that lists\n * `@ekanos/sdk`. Textual on purpose — evaluating a partner's config module\n * would run arbitrary code; a lint-style scan does not.\n */\nfunction vitestInlinesSdk(source: string): boolean {\n const inlineArrayPattern = /inline\\s*:\\s*\\[([\\s\\S]*?)\\]/g;\n for (\n let match = inlineArrayPattern.exec(source);\n match !== null;\n match = inlineArrayPattern.exec(source)\n ) {\n if (/['\"]@ekanos\\/sdk['\"]/.test(match[1] ?? '')) return true;\n }\n return false;\n}\n"]}
1
+ {"version":3,"file":"project-checks.js","sourceRoot":"","sources":["../src/project-checks.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Finding } from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport { type EkanosProject, isDocUrl } from './project';\n\n/**\n * Every vitest/vite config basename `ekanos init` might have scaffolded (or a\n * partner might have renamed to). Exported so `pack.ts` can pack exactly the\n * same set it checks here — one list, so packing and validating this project\n * property can never disagree on what \"the test config\" even is.\n */\nexport const VITEST_CONFIG_NAMES = [\n 'vitest.config.ts',\n 'vitest.config.mts',\n 'vitest.config.cts',\n 'vitest.config.js',\n 'vitest.config.mjs',\n 'vitest.config.cjs',\n 'vite.config.ts',\n 'vite.config.mts',\n 'vite.config.js',\n 'vite.config.mjs',\n];\n\n/** The exact block the hint quotes — the one config that makes the SDK load. */\nconst REQUIRED_INLINE_BLOCK = [\n 'test: {',\n ' server: {',\n ' deps: {',\n \" inline: ['@ekanos/sdk'],\",\n ' },',\n ' },',\n '}',\n].join('\\n');\n\n/**\n * Project-level integrity checks that read files in the project root (next to\n * ekanos.json), NOT the integration definition. These are deliberately kept\n * out of the schema package's definition collectors: the definition is valid or\n * not on its own; whether the partner's TEST runner is configured to load the\n * published SDK is a property of THIS project.\n *\n * The highest-value check: a partner's vitest must inline `@ekanos/sdk`. The\n * published SDK dist imports extensionless `next/link`, so without\n * `test.server.deps.inline: ['@ekanos/sdk']` vitest fails to load the SDK, the\n * test file silently imports nothing, and vitest reports green over zero tests.\n *\n * The check is conditional: if the project declares NO vitest/vite config at\n * all, there is nothing to assert (the `test` verb would surface a missing\n * runner on its own). If a config IS present, it MUST inline the SDK.\n */\nexport function collectProjectFindings(projectDir: string): Finding[] {\n const configFile = VITEST_CONFIG_NAMES.map((name) =>\n path.join(projectDir, name),\n ).find((candidate) => fs.existsSync(candidate));\n\n if (!configFile) return [];\n\n const source = fs.readFileSync(configFile, 'utf8');\n if (vitestInlinesSdk(source)) return [];\n\n return [\n {\n check: 'project.vitest-inline-sdk',\n severity: 'error',\n file: configFile,\n message:\n `${path.basename(configFile)} does not inline @ekanos/sdk. The ` +\n `published SDK dist imports extensionless \"next/link\", so without ` +\n `test.server.deps.inline including \"@ekanos/sdk\", vitest cannot load ` +\n `the SDK — the test file imports nothing and vitest reports green ` +\n `over zero tests.`,\n hint:\n `Add this to your vitest config's defineConfig so the SDK is ` +\n `transformed for the test runner:\\n\\n${REQUIRED_INLINE_BLOCK}`,\n },\n ];\n}\n\n/**\n * Advisory check on the `docs` array: a relative entry that resolves to\n * nothing on disk gets a WARNING — never an error, because a missing doc file\n * must not block a publish (the gate refuses only error-severity findings).\n * URLs are never checked: `validate` does no network, ever, and an agent\n * dereferences them at authoring time instead.\n */\nexport function collectDocsFindings(\n project: EkanosProject,\n projectDir: string,\n): Finding[] {\n const findings: Finding[] = [];\n\n for (const entry of project.docs ?? []) {\n if (isDocUrl(entry)) continue;\n\n const resolved = path.resolve(projectDir, entry);\n if (fs.existsSync(resolved)) continue;\n\n findings.push({\n check: 'docs/missing-file',\n severity: 'warn',\n file: resolved,\n message:\n `ekanos.json lists \"${entry}\" under \"docs\", but no file exists ` +\n `there (resolved to ${resolved}).`,\n hint:\n `Create ${entry}, or fix the path in ekanos.json's \"docs\" array so ` +\n 'it points at real API documentation.',\n });\n }\n\n return findings;\n}\n\n/**\n * True when the config source contains an `inline: [ … ]` array that lists\n * `@ekanos/sdk`. Textual on purpose — evaluating a partner's config module\n * would run arbitrary code; a lint-style scan does not.\n */\nfunction vitestInlinesSdk(source: string): boolean {\n const inlineArrayPattern = /inline\\s*:\\s*\\[([\\s\\S]*?)\\]/g;\n for (\n let match = inlineArrayPattern.exec(source);\n match !== null;\n match = inlineArrayPattern.exec(source)\n ) {\n if (/['\"]@ekanos\\/sdk['\"]/.test(match[1] ?? '')) return true;\n }\n return false;\n}\n"]}