@tangle-network/agent-app 0.43.56 → 0.43.58
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.
- package/dist/DesignCanvas-UNL34LS2.js +12 -0
- package/dist/DesignCanvasEditor-FJIVYOA2.js +13 -0
- package/dist/IntakeInterview-3ZIQMZS6.js +8 -0
- package/dist/InvitationsPanel-CJ7DR4F7.js +8 -0
- package/dist/MembersPanel-BB4OD2KB.js +8 -0
- package/dist/{TimelineEditor-I35SJJAJ.js → TimelineEditor-2ECKSU6P.js} +3 -3
- package/dist/{VaultPane-DrQ_tH6c.d.ts → VaultPane-BDP6SB_K.d.ts} +1 -0
- package/dist/{access-BZ81Btt5.d.ts → access-490O6aOU.d.ts} +16 -1
- package/dist/app-auth/index.d.ts +6 -1
- package/dist/app-auth/index.js +3 -3
- package/dist/app-auth/index.js.map +1 -1
- package/dist/{apply-Gk4raT2j.d.ts → apply-6wlMOLf8.d.ts} +30 -1
- package/dist/assets/index.d.ts +41 -0
- package/dist/assets/index.js +1 -1
- package/dist/assistant/index.d.ts +26 -6
- package/dist/assistant/index.js +9 -9
- package/dist/assistant/index.js.map +1 -1
- package/dist/{attachment-validation-D0csjCvz.d.ts → attachment-validation-tPRp-PP1.d.ts} +7 -1
- package/dist/{auth-DuptSkWh.d.ts → auth-_FU8w01b.d.ts} +4 -1
- package/dist/billing/index.d.ts +8 -0
- package/dist/billing/index.js +1 -1
- package/dist/brand/index.d.ts +2 -0
- package/dist/brand/index.js.map +1 -1
- package/dist/brand-extraction/index.d.ts +3 -0
- package/dist/brand-extraction/index.js.map +1 -1
- package/dist/catalog/index.d.ts +2 -0
- package/dist/catalog/index.js +1 -1
- package/dist/chat-routes/index.d.ts +41 -10
- package/dist/chat-routes/index.js +15 -15
- package/dist/chat-routes/index.js.map +1 -1
- package/dist/chat-store/index.d.ts +18 -4
- package/dist/chat-store/index.js +4 -4
- package/dist/chat-store/index.js.map +1 -1
- package/dist/{chunk-H5FM75MR.js → chunk-22GLESKE.js} +3 -3
- package/dist/chunk-22GLESKE.js.map +1 -0
- package/dist/{chunk-WEBBJBDH.js → chunk-2DRYTJHI.js} +1 -1
- package/dist/chunk-2DRYTJHI.js.map +1 -0
- package/dist/{chunk-7EVZUIHW.js → chunk-3EJ6SFJI.js} +1 -1
- package/dist/chunk-3EJ6SFJI.js.map +1 -0
- package/dist/{chunk-HRJJH3RX.js → chunk-3OFQFW5K.js} +4 -4
- package/dist/chunk-3OFQFW5K.js.map +1 -0
- package/dist/{chunk-7SUPA2YT.js → chunk-4KKXZQPT.js} +2 -2
- package/dist/chunk-4KKXZQPT.js.map +1 -0
- package/dist/{chunk-5PTGEJZL.js → chunk-5SD6HT2V.js} +1 -1
- package/dist/chunk-5SD6HT2V.js.map +1 -0
- package/dist/{chunk-7C64WKAH.js → chunk-5SXS3YAB.js} +2 -2
- package/dist/{chunk-L2TG5DBW.js → chunk-5TESA4SN.js} +1 -1
- package/dist/chunk-5TESA4SN.js.map +1 -0
- package/dist/{chunk-63CE7FEZ.js → chunk-6XIAPIW6.js} +1 -1
- package/dist/chunk-6XIAPIW6.js.map +1 -0
- package/dist/{chunk-MFRCM32T.js → chunk-7CTIUCQ4.js} +1 -1
- package/dist/chunk-7CTIUCQ4.js.map +1 -0
- package/dist/{chunk-6KVH5SP5.js → chunk-7YW6EBDX.js} +2 -2
- package/dist/chunk-7YW6EBDX.js.map +1 -0
- package/dist/{chunk-ZXNXAQAH.js → chunk-AP2UXKUK.js} +1 -1
- package/dist/chunk-AP2UXKUK.js.map +1 -0
- package/dist/{chunk-K63OWUDJ.js → chunk-BPSV5AA2.js} +2 -2
- package/dist/chunk-BPSV5AA2.js.map +1 -0
- package/dist/{chunk-MFI4ZM7W.js → chunk-BT4QFCTB.js} +1 -1
- package/dist/chunk-BT4QFCTB.js.map +1 -0
- package/dist/{chunk-ZYBWGSAZ.js → chunk-BVKQKGRK.js} +1 -1
- package/dist/chunk-BVKQKGRK.js.map +1 -0
- package/dist/{chunk-RVUISYUE.js → chunk-C3NSB66C.js} +7 -7
- package/dist/chunk-C3NSB66C.js.map +1 -0
- package/dist/{chunk-BQV42AFK.js → chunk-CCVWR33L.js} +1 -1
- package/dist/chunk-CCVWR33L.js.map +1 -0
- package/dist/{chunk-MCJSS6SM.js → chunk-CQZSAR77.js} +1 -1
- package/dist/chunk-CQZSAR77.js.map +1 -0
- package/dist/{chunk-3SVAA3MA.js → chunk-DJ4VJIH5.js} +1 -1
- package/dist/chunk-DJ4VJIH5.js.map +1 -0
- package/dist/{chunk-XKBIYSSM.js → chunk-DTSPS2HV.js} +3 -3
- package/dist/chunk-DTSPS2HV.js.map +1 -0
- package/dist/{chunk-4QN75UHX.js → chunk-E7N67FYI.js} +8 -8
- package/dist/chunk-E7N67FYI.js.map +1 -0
- package/dist/{chunk-2QI7XV2T.js → chunk-FBVLEGEG.js} +1 -1
- package/dist/{chunk-2QI7XV2T.js.map → chunk-FBVLEGEG.js.map} +1 -1
- package/dist/{chunk-5RMIUJDI.js → chunk-FKCB5FTD.js} +1 -1
- package/dist/chunk-FKCB5FTD.js.map +1 -0
- package/dist/{chunk-EEPJGZJW.js → chunk-GPBRL2XR.js} +1 -1
- package/dist/chunk-GPBRL2XR.js.map +1 -0
- package/dist/{chunk-G3HCU7TA.js → chunk-GXE6KHTS.js} +1 -1
- package/dist/chunk-GXE6KHTS.js.map +1 -0
- package/dist/{chunk-65P3HJY3.js → chunk-HCOROIRT.js} +1 -1
- package/dist/chunk-HCOROIRT.js.map +1 -0
- package/dist/{chunk-54GSK2KK.js → chunk-HYTIHYNV.js} +2 -2
- package/dist/chunk-HYTIHYNV.js.map +1 -0
- package/dist/{chunk-5MG74GVQ.js → chunk-IG46XCZM.js} +3 -3
- package/dist/chunk-IG46XCZM.js.map +1 -0
- package/dist/{chunk-ND3XEGBE.js → chunk-JDEGS53O.js} +1 -1
- package/dist/chunk-JDEGS53O.js.map +1 -0
- package/dist/{chunk-7W5XSTUF.js → chunk-JML7WKWU.js} +1 -1
- package/dist/chunk-JML7WKWU.js.map +1 -0
- package/dist/{chunk-Q4TKVF3L.js → chunk-JTLYXUEV.js} +1 -1
- package/dist/chunk-JTLYXUEV.js.map +1 -0
- package/dist/{chunk-CCRVDLV3.js → chunk-JWBZ74TW.js} +2 -2
- package/dist/chunk-JWBZ74TW.js.map +1 -0
- package/dist/{chunk-ZU5GNSOJ.js → chunk-K3LIPKFV.js} +3 -3
- package/dist/chunk-K3LIPKFV.js.map +1 -0
- package/dist/{chunk-GQRL6VNU.js → chunk-LGBO24FL.js} +1 -1
- package/dist/chunk-LGBO24FL.js.map +1 -0
- package/dist/{chunk-SWUVTGMR.js → chunk-MEUNTJL5.js} +3 -3
- package/dist/{chunk-SWUVTGMR.js.map → chunk-MEUNTJL5.js.map} +1 -1
- package/dist/{chunk-YNALYIQ3.js → chunk-NLSSFLLS.js} +1 -1
- package/dist/chunk-NLSSFLLS.js.map +1 -0
- package/dist/{chunk-HFC4BTWJ.js → chunk-PTUMBMVH.js} +1 -1
- package/dist/chunk-PTUMBMVH.js.map +1 -0
- package/dist/{chunk-R4NOKZMD.js → chunk-ROLFDOMJ.js} +3 -3
- package/dist/{chunk-NYATNLRK.js → chunk-RT5RKAFX.js} +1 -1
- package/dist/chunk-RT5RKAFX.js.map +1 -0
- package/dist/{chunk-GNL3MG5J.js → chunk-S564OFTL.js} +2 -2
- package/dist/{chunk-GUSCYE3S.js → chunk-TQOFR6XY.js} +1 -1
- package/dist/chunk-TQOFR6XY.js.map +1 -0
- package/dist/{chunk-47C6PJCW.js → chunk-TZO3SOUL.js} +1 -1
- package/dist/chunk-TZO3SOUL.js.map +1 -0
- package/dist/{chunk-YGUNTIT5.js → chunk-UKTYKG57.js} +1 -1
- package/dist/chunk-UKTYKG57.js.map +1 -0
- package/dist/{chunk-23LUHHHN.js → chunk-VCOD5AOR.js} +1 -1
- package/dist/chunk-VCOD5AOR.js.map +1 -0
- package/dist/{chunk-5I72FRZY.js → chunk-VOJB7MVG.js} +2 -2
- package/dist/{chunk-XWJXZ6WE.js → chunk-VTWKH4YU.js} +2 -2
- package/dist/chunk-VTWKH4YU.js.map +1 -0
- package/dist/{chunk-4K7BZYO7.js → chunk-VWAEWOWK.js} +3 -3
- package/dist/chunk-VWAEWOWK.js.map +1 -0
- package/dist/{chunk-M2EBUDZ7.js → chunk-VWOPOLVO.js} +2 -2
- package/dist/chunk-VWOPOLVO.js.map +1 -0
- package/dist/{chunk-BN2USWIR.js → chunk-VYECQAGM.js} +2 -2
- package/dist/chunk-VYECQAGM.js.map +1 -0
- package/dist/{chunk-SIXYZ2FB.js → chunk-YJMCRXQQ.js} +1 -1
- package/dist/chunk-YJMCRXQQ.js.map +1 -0
- package/dist/{chunk-PJC4NXPA.js → chunk-YKBDH2UY.js} +3 -3
- package/dist/chunk-YKBDH2UY.js.map +1 -0
- package/dist/{chunk-XAWFPMAR.js → chunk-YKOM4ZLQ.js} +1 -1
- package/dist/chunk-YKOM4ZLQ.js.map +1 -0
- package/dist/{chunk-TKVJE63N.js → chunk-YRMLYFVR.js} +3 -3
- package/dist/chunk-YRMLYFVR.js.map +1 -0
- package/dist/{chunk-USYXHDKE.js → chunk-YZ6KQULN.js} +2 -2
- package/dist/{command-stack-B_-WNfZU.d.ts → command-stack-TNPWJCzW.d.ts} +14 -2
- package/dist/{completion-Kaqp_tWk.d.ts → completion-CvcNUz07.d.ts} +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/{contract-KfqJh_au.d.ts → contract-TjB68uqA.d.ts} +17 -0
- package/dist/design-canvas/drizzle.d.ts +10 -2
- package/dist/design-canvas/drizzle.js.map +1 -1
- package/dist/design-canvas/index.d.ts +29 -11
- package/dist/design-canvas/index.js +1070 -17
- package/dist/design-canvas/index.js.map +1 -1
- package/dist/design-canvas-react/engine.d.ts +42 -6
- package/dist/design-canvas-react/engine.js +4 -4
- package/dist/design-canvas-react/index.d.ts +12 -7
- package/dist/design-canvas-react/index.js +11 -11
- package/dist/design-canvas-react/index.js.map +1 -1
- package/dist/design-canvas-react/lazy.d.ts +4 -4
- package/dist/design-canvas-react/lazy.js +1 -1
- package/dist/durable-chat/index.d.ts +46 -1
- package/dist/durable-chat/index.js +3 -3
- package/dist/eval/index.d.ts +1 -1
- package/dist/{export-presets-DAsU5Wal.d.ts → export-presets-mgVulRaV.d.ts} +10 -1
- package/dist/{flow-types-Cb_AblZs.d.ts → flow-types-CqomVAUN.d.ts} +1 -0
- package/dist/harness/index.d.ts +5 -0
- package/dist/harness/index.js +1 -1
- package/dist/index.d.ts +10 -18
- package/dist/index.js +30 -231
- package/dist/intakes/api.d.ts +3 -2
- package/dist/intakes/api.js +3 -3
- package/dist/intakes/api.js.map +1 -1
- package/dist/intakes/drizzle.d.ts +10 -2
- package/dist/intakes/drizzle.js +3 -3
- package/dist/intakes/drizzle.js.map +1 -1
- package/dist/intakes/index.d.ts +2 -2
- package/dist/intakes/index.js +2 -2
- package/dist/intakes-react/index.d.ts +2 -1
- package/dist/intakes-react/index.js +2 -2
- package/dist/intakes-react/lazy.d.ts +2 -1
- package/dist/intakes-react/lazy.js +1 -1
- package/dist/intakes-react/lazy.js.map +1 -1
- package/dist/integrations/index.d.ts +4 -0
- package/dist/integrations/index.js +1 -1
- package/dist/interactions/index.d.ts +13 -2
- package/dist/interactions/index.js +2 -2
- package/dist/{invitations-CZ5G2tIn.d.ts → invitations-DoYMvXea.d.ts} +11 -1
- package/dist/{invitations-schema-DaMO4hZE.d.ts → invitations-schema-_fI7HkJP.d.ts} +5 -1
- package/dist/knowledge/index.d.ts +2 -0
- package/dist/knowledge/index.js +1 -1
- package/dist/knowledge-loop/index.d.ts +4 -1
- package/dist/knowledge-loop/index.js +1 -1
- package/dist/{lazy-C7LiVeFt.d.ts → lazy-DrkVyDpe.d.ts} +2 -2
- package/dist/{mcp-BHfIoGLW.d.ts → mcp-BjPqQ-3C.d.ts} +4 -2
- package/dist/{mcp-rpc-DLw_r9PQ.d.ts → mcp-rpc-BfUOsalw.d.ts} +3 -0
- package/dist/missions/index.d.ts +25 -0
- package/dist/missions/index.js +1 -1
- package/dist/{model-Bzi5i63l.d.ts → model-C8U0HZxL.d.ts} +1 -0
- package/dist/{model-dF2h4xT9.d.ts → model-DmdkIteM.d.ts} +19 -0
- package/dist/{model-BBwyOuWG.d.ts → model-DnfO_PdJ.d.ts} +25 -1
- package/dist/model-resolution/index.d.ts +10 -0
- package/dist/model-resolution/index.js.map +1 -1
- package/dist/{operations-DLIvvD00.d.ts → operations-ByJ6yXOW.d.ts} +20 -2
- package/dist/{parts-1sRYSPjF.d.ts → parts-n9XUon0a.d.ts} +29 -1
- package/dist/plans/index.d.ts +6 -0
- package/dist/plans/index.js +1 -1
- package/dist/platform/index.d.ts +24 -2
- package/dist/platform/index.js +3 -3
- package/dist/platform/index.js.map +1 -1
- package/dist/preflight/index.d.ts +3 -0
- package/dist/preflight/index.js +1 -1
- package/dist/preset-cloudflare/index.d.ts +4 -1
- package/dist/preset-cloudflare/index.js +2 -2
- package/dist/redact/index.d.ts +5 -0
- package/dist/redact/index.js +1 -1
- package/dist/{roles-BC1n4t37.d.ts → roles-B4nU3jDi.d.ts} +12 -0
- package/dist/run/index.d.ts +3 -0
- package/dist/run/index.js +1 -1
- package/dist/run/index.js.map +1 -1
- package/dist/runtime/index.d.ts +11 -4
- package/dist/runtime/index.js +4 -4
- package/dist/sandbox/index.d.ts +96 -3
- package/dist/sandbox/index.js +6 -6
- package/dist/{sandbox-terminal-BIIC__CP.d.ts → sandbox-terminal-ChNEdHF8.d.ts} +5 -0
- package/dist/sequences/drizzle.d.ts +11 -1
- package/dist/sequences/drizzle.js +1 -1
- package/dist/sequences/drizzle.js.map +1 -1
- package/dist/sequences/index.d.ts +32 -7
- package/dist/sequences/index.js +1562 -47
- package/dist/sequences/index.js.map +1 -1
- package/dist/sequences-react/index.d.ts +32 -2
- package/dist/sequences-react/index.js +3 -3
- package/dist/sequences-react/index.js.map +1 -1
- package/dist/{sso-CNOsARMJ.d.ts → sso-Cm00S61u.d.ts} +13 -0
- package/dist/{stale-turn-lock-C8Na1cFZ.d.ts → stale-turn-lock-DucQzvXu.d.ts} +2 -0
- package/dist/store/index.d.ts +5 -0
- package/dist/store/index.js.map +1 -1
- package/dist/{store-gckrNq-g.d.ts → store-B7LLlk9p.d.ts} +22 -1
- package/dist/{store-CFyxgTlD.d.ts → store-CqfDtnPQ.d.ts} +8 -2
- package/dist/stream/index.d.ts +10 -4
- package/dist/stream/index.js +4 -4
- package/dist/{stream-normalizer-DWvtmY6F.d.ts → stream-normalizer-C3M--r6y.d.ts} +17 -1
- package/dist/studio/index.d.ts +37 -0
- package/dist/studio/index.js +1 -1
- package/dist/studio-react/index.d.ts +3 -0
- package/dist/studio-react/index.js +1 -1
- package/dist/studio-react/index.js.map +1 -1
- package/dist/tangle/index.d.ts +3 -0
- package/dist/tangle/index.js +1 -1
- package/dist/teams/drizzle.d.ts +8 -4
- package/dist/teams/drizzle.js +1 -1
- package/dist/teams/drizzle.js.map +1 -1
- package/dist/teams/index.d.ts +4 -2
- package/dist/teams/index.js +3 -3
- package/dist/teams/invitations-api.d.ts +10 -4
- package/dist/teams/invitations-api.js +4 -4
- package/dist/teams/invitations-api.js.map +1 -1
- package/dist/teams/members-api.d.ts +4 -2
- package/dist/teams/members-api.js +3 -3
- package/dist/teams/resend.d.ts +5 -4
- package/dist/teams/resend.js +1 -1
- package/dist/teams/resend.js.map +1 -1
- package/dist/teams-react/index.d.ts +7 -2
- package/dist/teams-react/index.js +3 -3
- package/dist/teams-react/lazy.d.ts +5 -2
- package/dist/teams-react/lazy.js +2 -2
- package/dist/teams-react/lazy.js.map +1 -1
- package/dist/theme/index.d.ts +2 -0
- package/dist/theme/index.js +1 -1
- package/dist/theme/tailwind-preset.d.ts +1 -0
- package/dist/theme/tailwind-preset.js.map +1 -1
- package/dist/theme-contract/cli.js +1 -1
- package/dist/theme-contract/index.d.ts +3 -0
- package/dist/theme-contract/index.js +1 -1
- package/dist/tools/index.d.ts +13 -6
- package/dist/tools/index.js +3 -3
- package/dist/trace/index.d.ts +6 -1
- package/dist/trace/index.js +2 -2
- package/dist/{turn-buffer-C9mEgoop.d.ts → turn-buffer-DGnAPKwa.d.ts} +6 -0
- package/dist/turn-stream/index.d.ts +28 -2
- package/dist/turn-stream/index.js +1 -1
- package/dist/turn-stream/index.js.map +1 -1
- package/dist/{types-BEOvc_ue.d.ts → types-CBRyqijY.d.ts} +10 -0
- package/dist/vault/index.d.ts +1 -1
- package/dist/vault/lazy.d.ts +3 -2
- package/dist/vault/lazy.js.map +1 -1
- package/dist/web/index.d.ts +4 -0
- package/dist/web/index.js +1 -1
- package/dist/web-react/index.d.ts +51 -8
- package/dist/web-react/index.js +9 -9
- package/dist/web-react/terminal.d.ts +2 -2
- package/dist/web-react/terminal.js +1 -1
- package/package.json +3 -2
- package/dist/DesignCanvas-5DJAFDNC.js +0 -12
- package/dist/DesignCanvasEditor-XUJZARSN.js +0 -13
- package/dist/IntakeInterview-WHVKMNQW.js +0 -8
- package/dist/InvitationsPanel-XUUWZBPV.js +0 -8
- package/dist/MembersPanel-FOVHWUQ3.js +0 -8
- package/dist/chunk-23LUHHHN.js.map +0 -1
- package/dist/chunk-3SVAA3MA.js.map +0 -1
- package/dist/chunk-47C6PJCW.js.map +0 -1
- package/dist/chunk-4K7BZYO7.js.map +0 -1
- package/dist/chunk-4QN75UHX.js.map +0 -1
- package/dist/chunk-54GSK2KK.js.map +0 -1
- package/dist/chunk-5MG74GVQ.js.map +0 -1
- package/dist/chunk-5PTGEJZL.js.map +0 -1
- package/dist/chunk-5RMIUJDI.js.map +0 -1
- package/dist/chunk-63CE7FEZ.js.map +0 -1
- package/dist/chunk-65P3HJY3.js.map +0 -1
- package/dist/chunk-6KVH5SP5.js.map +0 -1
- package/dist/chunk-7EVZUIHW.js.map +0 -1
- package/dist/chunk-7SUPA2YT.js.map +0 -1
- package/dist/chunk-7W5XSTUF.js.map +0 -1
- package/dist/chunk-BN2USWIR.js.map +0 -1
- package/dist/chunk-BQV42AFK.js.map +0 -1
- package/dist/chunk-CCRVDLV3.js.map +0 -1
- package/dist/chunk-EEPJGZJW.js.map +0 -1
- package/dist/chunk-G3HCU7TA.js.map +0 -1
- package/dist/chunk-GQRL6VNU.js.map +0 -1
- package/dist/chunk-GUSCYE3S.js.map +0 -1
- package/dist/chunk-H5FM75MR.js.map +0 -1
- package/dist/chunk-HFC4BTWJ.js.map +0 -1
- package/dist/chunk-HRJJH3RX.js.map +0 -1
- package/dist/chunk-K63OWUDJ.js.map +0 -1
- package/dist/chunk-L2TG5DBW.js.map +0 -1
- package/dist/chunk-M2EBUDZ7.js.map +0 -1
- package/dist/chunk-MCJSS6SM.js.map +0 -1
- package/dist/chunk-MFI4ZM7W.js.map +0 -1
- package/dist/chunk-MFRCM32T.js.map +0 -1
- package/dist/chunk-ND3XEGBE.js.map +0 -1
- package/dist/chunk-NEOV2NQ3.js +0 -1617
- package/dist/chunk-NEOV2NQ3.js.map +0 -1
- package/dist/chunk-NYATNLRK.js.map +0 -1
- package/dist/chunk-PJC4NXPA.js.map +0 -1
- package/dist/chunk-Q4TKVF3L.js.map +0 -1
- package/dist/chunk-RVUISYUE.js.map +0 -1
- package/dist/chunk-SIXYZ2FB.js.map +0 -1
- package/dist/chunk-TKVJE63N.js.map +0 -1
- package/dist/chunk-WEBBJBDH.js.map +0 -1
- package/dist/chunk-WFMUDX5J.js +0 -1092
- package/dist/chunk-WFMUDX5J.js.map +0 -1
- package/dist/chunk-XAWFPMAR.js.map +0 -1
- package/dist/chunk-XKBIYSSM.js.map +0 -1
- package/dist/chunk-XWJXZ6WE.js.map +0 -1
- package/dist/chunk-YGUNTIT5.js.map +0 -1
- package/dist/chunk-YNALYIQ3.js.map +0 -1
- package/dist/chunk-ZU5GNSOJ.js.map +0 -1
- package/dist/chunk-ZXNXAQAH.js.map +0 -1
- package/dist/chunk-ZYBWGSAZ.js.map +0 -1
- /package/dist/{DesignCanvas-5DJAFDNC.js.map → DesignCanvas-UNL34LS2.js.map} +0 -0
- /package/dist/{DesignCanvasEditor-XUJZARSN.js.map → DesignCanvasEditor-FJIVYOA2.js.map} +0 -0
- /package/dist/{IntakeInterview-WHVKMNQW.js.map → IntakeInterview-3ZIQMZS6.js.map} +0 -0
- /package/dist/{InvitationsPanel-XUUWZBPV.js.map → InvitationsPanel-CJ7DR4F7.js.map} +0 -0
- /package/dist/{MembersPanel-FOVHWUQ3.js.map → MembersPanel-BB4OD2KB.js.map} +0 -0
- /package/dist/{TimelineEditor-I35SJJAJ.js.map → TimelineEditor-2ECKSU6P.js.map} +0 -0
- /package/dist/{chunk-7C64WKAH.js.map → chunk-5SXS3YAB.js.map} +0 -0
- /package/dist/{chunk-R4NOKZMD.js.map → chunk-ROLFDOMJ.js.map} +0 -0
- /package/dist/{chunk-GNL3MG5J.js.map → chunk-S564OFTL.js.map} +0 -0
- /package/dist/{chunk-5I72FRZY.js.map → chunk-VOJB7MVG.js.map} +0 -0
- /package/dist/{chunk-USYXHDKE.js.map → chunk-YZ6KQULN.js.map} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { K as FileMention } from './parts-
|
|
1
|
+
import { K as FileMention } from './parts-n9XUon0a.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* `createSandboxFileIndexRoute` — server side of `@`-file-mentions
|
|
@@ -42,6 +42,7 @@ interface SandboxFileTreeSource {
|
|
|
42
42
|
maxDepth?: number;
|
|
43
43
|
}): Promise<SandboxTreeResult>;
|
|
44
44
|
}
|
|
45
|
+
/** Describe a ready file index response with workspace-relative entries and truncation status */
|
|
45
46
|
interface FileIndexReadyResponse {
|
|
46
47
|
status: 'ready';
|
|
47
48
|
/** Workspace-relative entries. Same shape as `FileMention` (`./wire`) so a
|
|
@@ -62,6 +63,7 @@ interface FileIndexReadyResponse {
|
|
|
62
63
|
interface FileIndexWarmingResponse {
|
|
63
64
|
status: 'warming';
|
|
64
65
|
}
|
|
66
|
+
/** Resolve a response indicating the file index is either ready or warming up */
|
|
65
67
|
type FileIndexResponse = FileIndexReadyResponse | FileIndexWarmingResponse;
|
|
66
68
|
/** Short-TTL cache seam so repeat popover opens in the same session don't
|
|
67
69
|
* re-scan the workspace. Host-provided (e.g. a KV binding); `key` is
|
|
@@ -72,6 +74,7 @@ interface FileIndexCache {
|
|
|
72
74
|
ttlSeconds?: number;
|
|
73
75
|
}): Promise<void> | void;
|
|
74
76
|
}
|
|
77
|
+
/** Define authorization details and parameters for indexing a file workspace with optional caching and ignore rules */
|
|
75
78
|
type FileIndexAuthorization = {
|
|
76
79
|
status: 'ready';
|
|
77
80
|
/** Structural sandbox `fs` handle, usually `ensureWorkspaceSandbox(...)` → `box.fs`. */
|
|
@@ -90,6 +93,7 @@ type FileIndexAuthorization = {
|
|
|
90
93
|
status: 'denied';
|
|
91
94
|
response: Response;
|
|
92
95
|
};
|
|
96
|
+
/** Define options to authorize and configure sandbox file index route behavior */
|
|
93
97
|
interface CreateSandboxFileIndexRouteOptions {
|
|
94
98
|
/** Authenticate the caller, resolve the sandbox `fs` handle, and signal a
|
|
95
99
|
* cold box — never provisions or waits. */
|
|
@@ -109,6 +113,7 @@ interface CreateSandboxFileIndexRouteOptions {
|
|
|
109
113
|
/** Cache TTL in seconds when `cache` is set. Default 20. */
|
|
110
114
|
cacheTtlSeconds?: number;
|
|
111
115
|
}
|
|
116
|
+
/** Resolve a sandbox file index route with authorization, caching, and configurable depth and entries limits */
|
|
112
117
|
declare function createSandboxFileIndexRoute(options: CreateSandboxFileIndexRouteOptions): (request: Request) => Promise<Response>;
|
|
113
118
|
|
|
114
119
|
/**
|
|
@@ -178,6 +183,7 @@ declare const ATTACHMENT_ACCEPT = "image/*,.pdf,.txt,.md,.csv,.json,.yaml,.yml,.
|
|
|
178
183
|
* Values must match `sniffBinary`'s output strings verbatim, or every
|
|
179
184
|
* upload of that format fails the type gate. */
|
|
180
185
|
declare const ALLOWED_ATTACHMENT_SNIFFED_MIMES: ReadonlySet<string>;
|
|
186
|
+
/** Represent the result of checking an attachment's type with success or specific failure details */
|
|
181
187
|
type AttachmentTypeCheckResult = {
|
|
182
188
|
succeeded: true;
|
|
183
189
|
} | {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as AppToolContext } from './types-
|
|
1
|
+
import { c as AppToolContext } from './types-CBRyqijY.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Header names carrying the server-set per-turn context + the capability token.
|
|
@@ -10,13 +10,16 @@ interface ToolHeaderNames {
|
|
|
10
10
|
workspaceId: string;
|
|
11
11
|
threadId: string;
|
|
12
12
|
}
|
|
13
|
+
/** Provide default HTTP header names for user, workspace, and thread identification */
|
|
13
14
|
declare const DEFAULT_HEADER_NAMES: ToolHeaderNames;
|
|
15
|
+
/** Define options to verify bearer tokens and customize authentication header names */
|
|
14
16
|
interface AuthenticateOptions {
|
|
15
17
|
/** Verify the bearer capability token belongs to `userId`. The product's
|
|
16
18
|
* HMAC/JWT impl — the seam that keeps token crypto out of this package. */
|
|
17
19
|
verifyToken: (userId: string, bearer: string) => Promise<boolean>;
|
|
18
20
|
headerNames?: ToolHeaderNames;
|
|
19
21
|
}
|
|
22
|
+
/** Represent the result of tool authentication with success context or failure response */
|
|
20
23
|
type ToolAuthResult = {
|
|
21
24
|
ok: true;
|
|
22
25
|
ctx: AppToolContext;
|
package/dist/billing/index.d.ts
CHANGED
|
@@ -102,6 +102,7 @@ interface KeyCrypto {
|
|
|
102
102
|
encrypt(secret: string): Promise<string>;
|
|
103
103
|
decrypt(encrypted: string): Promise<string>;
|
|
104
104
|
}
|
|
105
|
+
/** Define configuration options for managing workspace keys including provisioning, storage, and cryptography */
|
|
105
106
|
interface WorkspaceKeyManagerOptions {
|
|
106
107
|
provisioner: KeyProvisioner;
|
|
107
108
|
store: WorkspaceKeyStore;
|
|
@@ -113,6 +114,7 @@ interface WorkspaceKeyManagerOptions {
|
|
|
113
114
|
/** tcloud product the key is scoped to. Default `'router'`. */
|
|
114
115
|
product?: string;
|
|
115
116
|
}
|
|
117
|
+
/** Describe usage and budget details for a workspace model key including expiration and exhaustion status */
|
|
116
118
|
interface WorkspaceModelKeyUsage {
|
|
117
119
|
keyId: string;
|
|
118
120
|
budgetUsd: number;
|
|
@@ -121,6 +123,7 @@ interface WorkspaceModelKeyUsage {
|
|
|
121
123
|
expiresAt: string | null;
|
|
122
124
|
exhausted: boolean;
|
|
123
125
|
}
|
|
126
|
+
/** Manage workspace keys by ensuring, rotating, and tracking usage of active child-key secrets */
|
|
124
127
|
interface WorkspaceKeyManager {
|
|
125
128
|
/** The workspace's active child-key secret, provisioning one if absent/expired. */
|
|
126
129
|
ensureKey(workspaceId: string, opts?: {
|
|
@@ -185,6 +188,7 @@ interface PlatformBillingClient<Plan extends string> {
|
|
|
185
188
|
referenceId: string;
|
|
186
189
|
}): Promise<void>;
|
|
187
190
|
}
|
|
191
|
+
/** Define shared billing state including user ID, plan, balances, concurrency, and overage permission */
|
|
188
192
|
interface SharedBillingState<Plan extends string> {
|
|
189
193
|
/** Platform user id, or null when the user has no Tangle SSO account. */
|
|
190
194
|
platformUserId: string | null;
|
|
@@ -195,6 +199,7 @@ interface SharedBillingState<Plan extends string> {
|
|
|
195
199
|
concurrency: number;
|
|
196
200
|
overageAllowed: boolean;
|
|
197
201
|
}
|
|
202
|
+
/** Define configuration options for managing platform balance based on billing plans */
|
|
198
203
|
interface PlatformBalanceManagerOptions<Plan extends string> {
|
|
199
204
|
client: PlatformBillingClient<Plan>;
|
|
200
205
|
/** Plan → limits map (the product's pricing). */
|
|
@@ -204,6 +209,7 @@ interface PlatformBalanceManagerOptions<Plan extends string> {
|
|
|
204
209
|
/** The product slug to attribute usage to (for `getProductUsage`). */
|
|
205
210
|
productSlug: string;
|
|
206
211
|
}
|
|
212
|
+
/** Manage user plans and balances including state retrieval, billing authorization, deduction, and usage tracking */
|
|
207
213
|
interface PlatformBalanceManager<Plan extends string> {
|
|
208
214
|
/** Resolve the user's plan + balance. Unlinked or platform-outage users fail
|
|
209
215
|
* CLOSED: free plan, zero remaining balance — a billable run is never started
|
|
@@ -229,7 +235,9 @@ interface PlatformBalanceManager<Plan extends string> {
|
|
|
229
235
|
transactionCount: number;
|
|
230
236
|
}>;
|
|
231
237
|
}
|
|
238
|
+
/** Create a platform balance manager to handle user plan limits and state based on provided options */
|
|
232
239
|
declare function createPlatformBalanceManager<Plan extends string>(opts: PlatformBalanceManagerOptions<Plan>): PlatformBalanceManager<Plan>;
|
|
240
|
+
/** Create a workspace key manager that handles key provisioning and budget tracking */
|
|
233
241
|
declare function createWorkspaceKeyManager(opts: WorkspaceKeyManagerOptions): WorkspaceKeyManager;
|
|
234
242
|
|
|
235
243
|
export { type KeyCrypto, type KeyProvisioner, type PlanLimit, type PlatformBalanceInfo, type PlatformBalanceManager, type PlatformBalanceManagerOptions, type PlatformBillingClient, type PlatformIdentity, type PlatformProductUsage, type SharedBillingState, type TcloudKeyClient, type WorkspaceKeyManager, type WorkspaceKeyManagerOptions, type WorkspaceKeyRecord, type WorkspaceKeyStore, type WorkspaceModelKeyUsage, createPlatformBalanceManager, createTcloudKeyProvisioner, createWorkspaceKeyManager };
|
package/dist/billing/index.js
CHANGED
package/dist/brand/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
|
|
4
|
+
/** Define properties to customize the logo variant, size, style, and icon display options */
|
|
4
5
|
interface LogoProps {
|
|
5
6
|
/** Reserved for future lockups; only the default ('sandbox') exists today. */
|
|
6
7
|
variant?: 'sandbox';
|
|
@@ -19,6 +20,7 @@ declare function TangleKnot({ size, className }: {
|
|
|
19
20
|
* wordmark paints with `currentColor` so it inherits the surrounding text color
|
|
20
21
|
* and adapts to light/dark automatically. */
|
|
21
22
|
declare function Logo({ variant, size, className, iconOnly }: LogoProps): react.JSX.Element;
|
|
23
|
+
/** Define properties for a brand header including optional title, children, and CSS class name */
|
|
22
24
|
interface BrandHeaderProps {
|
|
23
25
|
/** Product name rendered next to the knot. Omit for a mark-only header. */
|
|
24
26
|
title?: string;
|
package/dist/brand/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/brand/index.tsx"],"sourcesContent":["/**\n * Tangle brand spine — the single place that supplies the Tangle logotype to\n * every agent-app React surface, so products stop fork-duplicating the mark.\n *\n * import { Logo, TangleKnot, BrandHeader } from '@tangle-network/agent-app/brand'\n *\n * The mark is vendored as dependency-free inline SVG — the SAME asset the\n * sandbox product ships (web/public/tangle-logo.svg) — rather than re-exported\n * from `@tangle-network/sandbox-ui`. sandbox-ui's logo drags a heavy, opt-in\n * peer chain (`@tangle-network/ui` → `@tangle-network/brand` → `@nanostores/*`)\n * that a dependency-light shell must not require to render its own logo; the SVG\n * IS the brand, so vendoring it keeps `/brand` importable anywhere (browser,\n * edge, tests, SSR) with no peers. The knot keeps the brand gradient; the\n * wordmark paints with `currentColor` so it adapts to light/dark automatically.\n *\n * `LogoProps` mirrors sandbox-ui's signature so `Logo` is a drop-in.\n */\nimport type { ReactNode } from 'react'\n\nexport interface LogoProps {\n /** Reserved for future lockups; only the default ('sandbox') exists today. */\n variant?: 'sandbox'\n size?: 'sm' | 'md' | 'lg' | 'xl'\n className?: string\n /** Render the knot mark alone, without the wordmark. */\n iconOnly?: boolean\n}\n\n// Absolute path data lifted verbatim from the canonical tangle-logo.svg (the\n// 564×228 lockup). The two knot paths and the wordmark share that coordinate\n// space, so the icon and the full lockup reuse the same geometry + gradients.\nconst KNOT_PATH_A =\n 'M170.74 150.082C170.747 142.848 167.464 135.908 161.612 130.784C155.76 125.66 147.818 122.772 139.528 122.754L104.921 122.754C104.704 119.939 104.567 117.062 104.567 114.078C104.567 111.095 104.429 108.231 104.236 105.403L139.528 105.403C147.746 105.288 155.582 102.359 161.347 97.2467C167.112 92.135 170.343 85.2506 170.343 78.0787C170.343 70.9069 167.112 64.0225 161.347 58.9107C155.582 53.799 147.746 50.8696 139.528 50.7545L56.817 50.7545C48.5993 50.8696 40.7628 53.799 34.9981 58.9107C29.2334 64.0225 26.0025 70.9069 26.0025 78.0787C26.0025 85.2506 29.2334 92.135 34.9981 97.2467C40.7628 102.359 48.5993 105.288 56.817 105.403L89.3238 106.163C91.5854 106.163 91.7785 111.095 91.7785 114.078C91.7785 117.062 91.9156 119.925 92.1091 122.754L56.817 122.754C48.5993 122.869 40.7628 125.798 34.9981 130.91C29.2334 136.022 26.0025 142.906 26.0025 150.078C26.0025 157.25 29.2334 164.134 34.9981 169.246C40.7628 174.358 48.5993 177.287 56.817 177.402L139.528 177.402C147.816 177.384 155.757 174.497 161.609 169.374C167.461 164.252 170.745 157.314 170.74 150.082ZM157.952 78.0752C157.954 82.3443 156.016 86.4397 152.562 89.463C149.108 92.4863 144.42 94.1905 139.528 94.2017L102.881 94.2017C101.554 86.2073 99.0244 78.4005 95.3585 70.9829C93.7421 67.7691 91.6728 64.7438 89.1983 61.9769L139.528 61.9769C144.415 61.988 149.097 63.6884 152.55 66.7056C156.003 69.7228 157.946 73.811 157.952 78.0752ZM56.817 94.2017C51.9157 94.2017 47.2151 92.5027 43.7493 89.4784C40.2835 86.4541 38.3364 82.3522 38.3364 78.0752C38.3364 73.7982 40.2835 69.6964 43.7493 66.6721C47.2151 63.6478 51.9157 61.9487 56.817 61.9487L65.1139 61.9487C72.4433 61.9487 79.3856 67.0146 83.7074 75.5071C86.6658 81.491 88.77 87.7697 89.9724 94.2017L56.817 94.2017ZM38.3929 150.082C38.3907 145.812 40.3293 141.717 43.7834 138.694C47.2374 135.67 51.9248 133.966 56.817 133.955L93.4637 133.955C94.7912 141.949 97.3206 149.756 100.987 157.174C102.603 160.388 104.672 163.413 107.147 166.18L56.817 166.18C51.9304 166.169 47.2479 164.468 43.7948 161.451C40.3416 158.434 38.3993 154.346 38.3929 150.082ZM112.686 152.65C109.728 146.666 107.623 140.387 106.421 133.955L139.528 133.955C144.429 133.955 149.13 135.654 152.596 138.678C156.062 141.703 158.009 145.804 158.009 150.082C158.009 154.359 156.062 158.46 152.596 161.485C149.13 164.509 144.429 166.208 139.528 166.208L131.231 166.208C123.934 166.208 116.992 161.142 112.686 152.65Z'\nconst KNOT_PATH_B =\n 'M170.74 78.0752C170.747 85.3089 167.463 92.2492 161.612 97.3727C155.76 102.496 147.817 105.384 139.527 105.403L104.92 105.403C104.702 108.217 104.565 111.095 104.565 114.078C104.565 117.062 104.428 119.925 104.235 122.754L139.527 122.754C147.745 122.869 155.582 125.798 161.347 130.91C167.112 136.022 170.342 142.906 170.342 150.078C170.342 157.25 167.112 164.134 161.347 169.246C155.582 174.358 147.745 177.287 139.527 177.402L56.8149 177.402C48.597 177.287 40.7604 174.358 34.9956 169.246C29.2307 164.134 25.9998 157.25 25.9998 150.078C25.9998 142.906 29.2307 136.022 34.9956 130.91C40.7604 125.798 48.597 122.869 56.8149 122.754L89.3223 121.994C91.5839 121.994 91.777 117.062 91.777 114.078C91.777 111.095 91.9141 108.231 92.1076 105.403L56.8149 105.403C48.597 105.288 40.7604 102.358 34.9956 97.2467C29.2307 92.135 25.9998 85.2506 25.9998 78.0787C25.9998 70.9069 29.2307 64.0225 34.9956 58.9107C40.7604 53.799 48.597 50.8695 56.8149 50.7545L139.527 50.7545C147.816 50.7731 155.757 53.6602 161.609 58.7822C167.46 63.9042 170.744 70.8428 170.74 78.0752ZM157.952 150.081C157.954 145.812 156.015 141.717 152.561 138.694C149.107 135.67 144.42 133.966 139.527 133.955L102.88 133.955C101.552 141.949 99.023 149.756 95.3571 157.174C93.7406 160.388 91.6712 163.413 89.1968 166.18L139.527 166.18C144.414 166.169 149.097 164.468 152.55 161.451C156.003 158.434 157.945 154.346 157.952 150.081ZM56.8149 133.955C51.9134 133.955 47.2127 135.654 43.7469 138.678C40.2811 141.703 38.334 145.804 38.334 150.081C38.334 154.358 40.2811 158.46 43.7469 161.485C47.2127 164.509 51.9134 166.208 56.8149 166.208L65.1119 166.208C72.4414 166.208 79.3838 161.142 83.7057 152.65C86.6642 146.666 88.7684 140.387 89.9708 133.955L56.8149 133.955ZM38.3904 78.0752C38.3883 82.3443 40.3269 86.4397 43.781 89.463C47.2351 92.4863 51.9226 94.1905 56.8149 94.2017L93.4622 94.2017C94.7898 86.2073 97.3192 78.4004 100.985 70.9829C102.602 67.7691 104.671 64.7438 107.145 61.9769L56.8149 61.9769C51.9282 61.988 47.2456 63.6884 43.7924 66.7056C40.3392 69.7228 38.3968 73.811 38.3904 78.0752ZM112.685 75.5071C109.726 81.491 107.622 87.7696 106.42 94.2017L139.527 94.2017C144.429 94.2017 149.13 92.5026 152.595 89.4783C156.061 86.454 158.008 82.3522 158.008 78.0752C158.008 73.7982 156.061 69.6964 152.595 66.6721C149.13 63.6478 144.429 61.9487 139.527 61.9487L131.23 61.9487C123.933 61.9487 116.991 67.0146 112.685 75.5071Z'\nconst WORDMARK_PATH =\n 'M244.353 87.6978V150.578H228.965V87.6978H244.353ZM209.018 94.5367V80.2889H264.3V94.5367H209.018ZM283.224 151.813C278.221 151.813 274.232 150.452 271.255 147.729C268.342 144.943 266.886 141.238 266.886 136.615C266.886 132.246 268.374 128.763 271.35 126.167C274.39 123.571 278.759 122.051 284.458 121.608L297.756 120.563V119.803C297.756 118.22 297.44 116.922 296.807 115.909C296.173 114.832 295.255 114.04 294.052 113.534C292.912 112.964 291.456 112.679 289.683 112.679C286.58 112.679 284.205 113.249 282.559 114.389C280.976 115.529 280.184 117.175 280.184 119.328H268.026C268.026 115.719 268.944 112.584 270.78 109.924C272.617 107.265 275.213 105.207 278.569 103.75C281.989 102.294 285.947 101.566 290.443 101.566C295.065 101.566 298.96 102.389 302.126 104.035C305.355 105.682 307.793 108.088 309.44 111.254C311.149 114.42 312.004 118.283 312.004 122.843V150.578H299.086L298.136 144.309C297.376 146.462 295.572 148.267 292.722 149.723C289.936 151.117 286.77 151.813 283.224 151.813ZM288.353 140.985C291.139 140.985 293.419 140.32 295.192 138.99C296.965 137.597 297.851 135.539 297.851 132.816V130.251L290.443 130.916C287.276 131.17 285.028 131.708 283.699 132.531C282.432 133.291 281.799 134.431 281.799 135.951C281.799 137.66 282.337 138.927 283.414 139.75C284.49 140.573 286.136 140.985 288.353 140.985ZM342.823 150.578H328.195V103.085H341.968L342.918 108.025C344.374 105.998 346.369 104.415 348.902 103.275C351.498 102.136 354.348 101.566 357.451 101.566C363.086 101.566 367.456 103.307 370.559 106.79C373.725 110.209 375.308 115.022 375.308 121.228V150.578H360.68V124.742C360.68 121.766 359.92 119.391 358.4 117.618C356.881 115.782 354.854 114.864 352.321 114.864C349.408 114.864 347.097 115.75 345.387 117.523C343.678 119.233 342.823 121.576 342.823 124.552V150.578ZM389.123 125.977C389.123 121.164 390.073 116.922 391.973 113.249C393.936 109.576 396.627 106.695 400.047 104.605C403.529 102.516 407.487 101.471 411.92 101.471C415.656 101.471 418.854 102.231 421.513 103.75C424.236 105.27 426.104 107.265 427.117 109.734L425.693 110.684L426.833 103.085H440.605V147.539C440.605 153.175 439.561 158.019 437.471 162.072C435.381 166.188 432.405 169.322 428.542 171.475C424.679 173.692 420.025 174.8 414.579 174.8C407.297 174.8 401.376 172.837 396.817 168.911C392.258 165.048 389.63 159.76 388.933 153.048H403.751C403.878 155.708 404.891 157.766 406.79 159.222C408.69 160.742 411.255 161.502 414.484 161.502C418.03 161.502 420.817 160.52 422.843 158.557C424.933 156.594 425.978 153.935 425.978 150.578V140.51L427.592 141.745C426.579 144.214 424.616 146.209 421.703 147.729C418.79 149.249 415.434 150.008 411.635 150.008C407.202 150.008 403.276 148.995 399.857 146.969C396.5 144.943 393.872 142.125 391.973 138.515C390.073 134.906 389.123 130.726 389.123 125.977ZM403.846 125.597C403.846 127.877 404.321 129.903 405.271 131.676C406.221 133.386 407.519 134.747 409.165 135.761C410.812 136.774 412.711 137.28 414.864 137.28C417.081 137.28 419.012 136.805 420.658 135.856C422.368 134.842 423.666 133.481 424.553 131.771C425.503 129.998 425.978 127.94 425.978 125.597C425.978 123.254 425.503 121.259 424.553 119.613C423.666 117.903 422.368 116.573 420.658 115.624C419.012 114.674 417.049 114.199 414.769 114.199C412.616 114.199 410.717 114.674 409.07 115.624C407.424 116.573 406.126 117.903 405.176 119.613C404.289 121.323 403.846 123.317 403.846 125.597ZM471.933 150.578H457.305V78.9591H471.933V150.578ZM510.643 151.813C505.893 151.813 501.651 150.737 497.915 148.584C494.242 146.431 491.329 143.486 489.176 139.75C487.086 135.951 486.041 131.613 486.041 126.737C486.041 121.798 487.055 117.46 489.081 113.724C491.171 109.924 494.052 106.948 497.725 104.795C501.397 102.642 505.608 101.566 510.358 101.566C515.36 101.566 519.666 102.611 523.276 104.7C526.885 106.727 529.671 109.639 531.635 113.439C533.598 117.175 534.579 121.639 534.579 126.832V130.536L493.735 130.726L493.925 121.703H520.046C520.046 119.17 519.191 117.175 517.482 115.719C515.772 114.199 513.429 113.439 510.453 113.439C507.983 113.439 505.957 113.914 504.374 114.864C502.854 115.814 501.714 117.302 500.954 119.328C500.194 121.291 499.814 123.824 499.814 126.927C499.814 131.36 500.701 134.652 502.474 136.805C504.31 138.895 507.128 139.94 510.928 139.94C513.714 139.94 516.025 139.465 517.862 138.515C519.698 137.565 520.869 136.236 521.376 134.526H534.769C533.946 139.782 531.35 143.993 526.98 147.159C522.611 150.262 517.165 151.813 510.643 151.813Z'\n\n/** Brand gradient + clip shared by the icon and the full lockup. Static ids are\n * fine: every instance defines the identical gradient, so a duplicate id in the\n * document resolves to an identical paint. */\nfunction KnotDefs() {\n return (\n <defs>\n <linearGradient id=\"tangleKnotA\" x1=\"36.79\" y1=\"58.78\" x2=\"145.99\" y2=\"183.59\" gradientUnits=\"userSpaceOnUse\">\n <stop stopColor=\"#8E59FF\" />\n <stop offset=\"1\" stopColor=\"#6888F9\" />\n </linearGradient>\n <linearGradient id=\"tangleKnotB\" x1=\"36.78\" y1=\"169.38\" x2=\"145.99\" y2=\"44.57\" gradientUnits=\"userSpaceOnUse\">\n <stop stopColor=\"#8E59FF\" />\n <stop offset=\"1\" stopColor=\"#6888F9\" />\n </linearGradient>\n <clipPath id=\"tangleKnotClip\">\n <rect width=\"126.648\" height=\"144.74\" fill=\"white\" transform=\"translate(170.74 50.7545) rotate(90)\" />\n </clipPath>\n </defs>\n )\n}\n\nfunction KnotPaths() {\n return (\n <g clipPath=\"url(#tangleKnotClip)\">\n <path d={KNOT_PATH_A} fill=\"url(#tangleKnotA)\" />\n <path opacity=\"0.8\" d={KNOT_PATH_B} fill=\"url(#tangleKnotB)\" />\n </g>\n )\n}\n\n/** Icon-only Tangle knot, brand gradient, theme-independent. `size` is the\n * rendered square in px. */\nexport function TangleKnot({ size = 24, className }: { size?: number; className?: string }) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"22 46 152 136\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={className}\n role=\"img\"\n aria-label=\"Tangle\"\n >\n <KnotPaths />\n <KnotDefs />\n </svg>\n )\n}\n\nconst WORDMARK_HEIGHTS: Record<NonNullable<LogoProps['size']>, number> = { sm: 16, md: 20, lg: 28, xl: 40 }\nconst LOCKUP_RATIO = 564 / 228\n\n/** Full Tangle lockup (knot + wordmark) or, with `iconOnly`, just the knot. The\n * wordmark paints with `currentColor` so it inherits the surrounding text color\n * and adapts to light/dark automatically. */\nexport function Logo({ variant = 'sandbox', size = 'md', className, iconOnly = false }: LogoProps) {\n void variant\n const height = WORDMARK_HEIGHTS[size]\n if (iconOnly) return <TangleKnot size={height} className={className} />\n return (\n <svg\n width={Math.round(height * LOCKUP_RATIO)}\n height={height}\n viewBox=\"0 0 564 228\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={className}\n role=\"img\"\n aria-label=\"Tangle\"\n >\n <KnotPaths />\n <path d={WORDMARK_PATH} fill=\"currentColor\" />\n <KnotDefs />\n </svg>\n )\n}\n\nexport interface BrandHeaderProps {\n /** Product name rendered next to the knot. Omit for a mark-only header. */\n title?: string\n /** Right-aligned slot for nav, actions, theme toggles. */\n children?: ReactNode\n className?: string\n}\n\n/**\n * Shared app-shell header: icon-only Tangle knot + optional product title on\n * the left, caller-supplied nav/actions on the right. Token-styled only.\n */\nexport function BrandHeader({ title, children, className }: BrandHeaderProps) {\n return (\n <header\n className={`flex shrink-0 items-center gap-3 border-b border-border bg-card px-4 py-2${\n className ? ` ${className}` : ''\n }`}\n >\n <span className=\"flex items-center gap-2\">\n <TangleKnot size={24} className=\"shrink-0\" />\n {title ? <span className=\"text-sm font-semibold text-foreground\">{title}</span> : null}\n </span>\n {children ? <div className=\"flex flex-1 items-center justify-end gap-1\">{children}</div> : null}\n </header>\n )\n}\n"],"mappings":";AA4CM,SACE,KADF;AAbN,IAAM,cACJ;AACF,IAAM,cACJ;AACF,IAAM,gBACJ;AAKF,SAAS,WAAW;AAClB,SACE,qBAAC,UACC;AAAA,yBAAC,oBAAe,IAAG,eAAc,IAAG,SAAQ,IAAG,SAAQ,IAAG,UAAS,IAAG,UAAS,eAAc,kBAC3F;AAAA,0BAAC,UAAK,WAAU,WAAU;AAAA,MAC1B,oBAAC,UAAK,QAAO,KAAI,WAAU,WAAU;AAAA,OACvC;AAAA,IACA,qBAAC,oBAAe,IAAG,eAAc,IAAG,SAAQ,IAAG,UAAS,IAAG,UAAS,IAAG,SAAQ,eAAc,kBAC3F;AAAA,0BAAC,UAAK,WAAU,WAAU;AAAA,MAC1B,oBAAC,UAAK,QAAO,KAAI,WAAU,WAAU;AAAA,OACvC;AAAA,IACA,oBAAC,cAAS,IAAG,kBACX,8BAAC,UAAK,OAAM,WAAU,QAAO,UAAS,MAAK,SAAQ,WAAU,wCAAuC,GACtG;AAAA,KACF;AAEJ;AAEA,SAAS,YAAY;AACnB,SACE,qBAAC,OAAE,UAAS,wBACV;AAAA,wBAAC,UAAK,GAAG,aAAa,MAAK,qBAAoB;AAAA,IAC/C,oBAAC,UAAK,SAAQ,OAAM,GAAG,aAAa,MAAK,qBAAoB;AAAA,KAC/D;AAEJ;AAIO,SAAS,WAAW,EAAE,OAAO,IAAI,UAAU,GAA0C;AAC1F,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAM;AAAA,MACN;AAAA,MACA,MAAK;AAAA,MACL,cAAW;AAAA,MAEX;AAAA,4BAAC,aAAU;AAAA,QACX,oBAAC,YAAS;AAAA;AAAA;AAAA,EACZ;AAEJ;AAEA,IAAM,mBAAmE,EAAE,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG;AAC1G,IAAM,eAAe,MAAM;AAKpB,SAAS,KAAK,EAAE,UAAU,WAAW,OAAO,MAAM,WAAW,WAAW,MAAM,GAAc;AACjG,OAAK;AACL,QAAM,SAAS,iBAAiB,IAAI;AACpC,MAAI,SAAU,QAAO,oBAAC,cAAW,MAAM,QAAQ,WAAsB;AACrE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,KAAK,MAAM,SAAS,YAAY;AAAA,MACvC;AAAA,MACA,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAM;AAAA,MACN;AAAA,MACA,MAAK;AAAA,MACL,cAAW;AAAA,MAEX;AAAA,4BAAC,aAAU;AAAA,QACX,oBAAC,UAAK,GAAG,eAAe,MAAK,gBAAe;AAAA,QAC5C,oBAAC,YAAS;AAAA;AAAA;AAAA,EACZ;AAEJ;AAcO,SAAS,YAAY,EAAE,OAAO,UAAU,UAAU,GAAqB;AAC5E,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,4EACT,YAAY,IAAI,SAAS,KAAK,EAChC;AAAA,MAEA;AAAA,6BAAC,UAAK,WAAU,2BACd;AAAA,8BAAC,cAAW,MAAM,IAAI,WAAU,YAAW;AAAA,UAC1C,QAAQ,oBAAC,UAAK,WAAU,yCAAyC,iBAAM,IAAU;AAAA,WACpF;AAAA,QACC,WAAW,oBAAC,SAAI,WAAU,8CAA8C,UAAS,IAAS;AAAA;AAAA;AAAA,EAC7F;AAEJ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/brand/index.tsx"],"sourcesContent":["/**\n * Tangle brand spine — the single place that supplies the Tangle logotype to\n * every agent-app React surface, so products stop fork-duplicating the mark.\n *\n * import { Logo, TangleKnot, BrandHeader } from '@tangle-network/agent-app/brand'\n *\n * The mark is vendored as dependency-free inline SVG — the SAME asset the\n * sandbox product ships (web/public/tangle-logo.svg) — rather than re-exported\n * from `@tangle-network/sandbox-ui`. sandbox-ui's logo drags a heavy, opt-in\n * peer chain (`@tangle-network/ui` → `@tangle-network/brand` → `@nanostores/*`)\n * that a dependency-light shell must not require to render its own logo; the SVG\n * IS the brand, so vendoring it keeps `/brand` importable anywhere (browser,\n * edge, tests, SSR) with no peers. The knot keeps the brand gradient; the\n * wordmark paints with `currentColor` so it adapts to light/dark automatically.\n *\n * `LogoProps` mirrors sandbox-ui's signature so `Logo` is a drop-in.\n */\nimport type { ReactNode } from 'react'\n\n/** Define properties to customize the logo variant, size, style, and icon display options */\nexport interface LogoProps {\n /** Reserved for future lockups; only the default ('sandbox') exists today. */\n variant?: 'sandbox'\n size?: 'sm' | 'md' | 'lg' | 'xl'\n className?: string\n /** Render the knot mark alone, without the wordmark. */\n iconOnly?: boolean\n}\n\n// Absolute path data lifted verbatim from the canonical tangle-logo.svg (the\n// 564×228 lockup). The two knot paths and the wordmark share that coordinate\n// space, so the icon and the full lockup reuse the same geometry + gradients.\nconst KNOT_PATH_A =\n 'M170.74 150.082C170.747 142.848 167.464 135.908 161.612 130.784C155.76 125.66 147.818 122.772 139.528 122.754L104.921 122.754C104.704 119.939 104.567 117.062 104.567 114.078C104.567 111.095 104.429 108.231 104.236 105.403L139.528 105.403C147.746 105.288 155.582 102.359 161.347 97.2467C167.112 92.135 170.343 85.2506 170.343 78.0787C170.343 70.9069 167.112 64.0225 161.347 58.9107C155.582 53.799 147.746 50.8696 139.528 50.7545L56.817 50.7545C48.5993 50.8696 40.7628 53.799 34.9981 58.9107C29.2334 64.0225 26.0025 70.9069 26.0025 78.0787C26.0025 85.2506 29.2334 92.135 34.9981 97.2467C40.7628 102.359 48.5993 105.288 56.817 105.403L89.3238 106.163C91.5854 106.163 91.7785 111.095 91.7785 114.078C91.7785 117.062 91.9156 119.925 92.1091 122.754L56.817 122.754C48.5993 122.869 40.7628 125.798 34.9981 130.91C29.2334 136.022 26.0025 142.906 26.0025 150.078C26.0025 157.25 29.2334 164.134 34.9981 169.246C40.7628 174.358 48.5993 177.287 56.817 177.402L139.528 177.402C147.816 177.384 155.757 174.497 161.609 169.374C167.461 164.252 170.745 157.314 170.74 150.082ZM157.952 78.0752C157.954 82.3443 156.016 86.4397 152.562 89.463C149.108 92.4863 144.42 94.1905 139.528 94.2017L102.881 94.2017C101.554 86.2073 99.0244 78.4005 95.3585 70.9829C93.7421 67.7691 91.6728 64.7438 89.1983 61.9769L139.528 61.9769C144.415 61.988 149.097 63.6884 152.55 66.7056C156.003 69.7228 157.946 73.811 157.952 78.0752ZM56.817 94.2017C51.9157 94.2017 47.2151 92.5027 43.7493 89.4784C40.2835 86.4541 38.3364 82.3522 38.3364 78.0752C38.3364 73.7982 40.2835 69.6964 43.7493 66.6721C47.2151 63.6478 51.9157 61.9487 56.817 61.9487L65.1139 61.9487C72.4433 61.9487 79.3856 67.0146 83.7074 75.5071C86.6658 81.491 88.77 87.7697 89.9724 94.2017L56.817 94.2017ZM38.3929 150.082C38.3907 145.812 40.3293 141.717 43.7834 138.694C47.2374 135.67 51.9248 133.966 56.817 133.955L93.4637 133.955C94.7912 141.949 97.3206 149.756 100.987 157.174C102.603 160.388 104.672 163.413 107.147 166.18L56.817 166.18C51.9304 166.169 47.2479 164.468 43.7948 161.451C40.3416 158.434 38.3993 154.346 38.3929 150.082ZM112.686 152.65C109.728 146.666 107.623 140.387 106.421 133.955L139.528 133.955C144.429 133.955 149.13 135.654 152.596 138.678C156.062 141.703 158.009 145.804 158.009 150.082C158.009 154.359 156.062 158.46 152.596 161.485C149.13 164.509 144.429 166.208 139.528 166.208L131.231 166.208C123.934 166.208 116.992 161.142 112.686 152.65Z'\nconst KNOT_PATH_B =\n 'M170.74 78.0752C170.747 85.3089 167.463 92.2492 161.612 97.3727C155.76 102.496 147.817 105.384 139.527 105.403L104.92 105.403C104.702 108.217 104.565 111.095 104.565 114.078C104.565 117.062 104.428 119.925 104.235 122.754L139.527 122.754C147.745 122.869 155.582 125.798 161.347 130.91C167.112 136.022 170.342 142.906 170.342 150.078C170.342 157.25 167.112 164.134 161.347 169.246C155.582 174.358 147.745 177.287 139.527 177.402L56.8149 177.402C48.597 177.287 40.7604 174.358 34.9956 169.246C29.2307 164.134 25.9998 157.25 25.9998 150.078C25.9998 142.906 29.2307 136.022 34.9956 130.91C40.7604 125.798 48.597 122.869 56.8149 122.754L89.3223 121.994C91.5839 121.994 91.777 117.062 91.777 114.078C91.777 111.095 91.9141 108.231 92.1076 105.403L56.8149 105.403C48.597 105.288 40.7604 102.358 34.9956 97.2467C29.2307 92.135 25.9998 85.2506 25.9998 78.0787C25.9998 70.9069 29.2307 64.0225 34.9956 58.9107C40.7604 53.799 48.597 50.8695 56.8149 50.7545L139.527 50.7545C147.816 50.7731 155.757 53.6602 161.609 58.7822C167.46 63.9042 170.744 70.8428 170.74 78.0752ZM157.952 150.081C157.954 145.812 156.015 141.717 152.561 138.694C149.107 135.67 144.42 133.966 139.527 133.955L102.88 133.955C101.552 141.949 99.023 149.756 95.3571 157.174C93.7406 160.388 91.6712 163.413 89.1968 166.18L139.527 166.18C144.414 166.169 149.097 164.468 152.55 161.451C156.003 158.434 157.945 154.346 157.952 150.081ZM56.8149 133.955C51.9134 133.955 47.2127 135.654 43.7469 138.678C40.2811 141.703 38.334 145.804 38.334 150.081C38.334 154.358 40.2811 158.46 43.7469 161.485C47.2127 164.509 51.9134 166.208 56.8149 166.208L65.1119 166.208C72.4414 166.208 79.3838 161.142 83.7057 152.65C86.6642 146.666 88.7684 140.387 89.9708 133.955L56.8149 133.955ZM38.3904 78.0752C38.3883 82.3443 40.3269 86.4397 43.781 89.463C47.2351 92.4863 51.9226 94.1905 56.8149 94.2017L93.4622 94.2017C94.7898 86.2073 97.3192 78.4004 100.985 70.9829C102.602 67.7691 104.671 64.7438 107.145 61.9769L56.8149 61.9769C51.9282 61.988 47.2456 63.6884 43.7924 66.7056C40.3392 69.7228 38.3968 73.811 38.3904 78.0752ZM112.685 75.5071C109.726 81.491 107.622 87.7696 106.42 94.2017L139.527 94.2017C144.429 94.2017 149.13 92.5026 152.595 89.4783C156.061 86.454 158.008 82.3522 158.008 78.0752C158.008 73.7982 156.061 69.6964 152.595 66.6721C149.13 63.6478 144.429 61.9487 139.527 61.9487L131.23 61.9487C123.933 61.9487 116.991 67.0146 112.685 75.5071Z'\nconst WORDMARK_PATH =\n 'M244.353 87.6978V150.578H228.965V87.6978H244.353ZM209.018 94.5367V80.2889H264.3V94.5367H209.018ZM283.224 151.813C278.221 151.813 274.232 150.452 271.255 147.729C268.342 144.943 266.886 141.238 266.886 136.615C266.886 132.246 268.374 128.763 271.35 126.167C274.39 123.571 278.759 122.051 284.458 121.608L297.756 120.563V119.803C297.756 118.22 297.44 116.922 296.807 115.909C296.173 114.832 295.255 114.04 294.052 113.534C292.912 112.964 291.456 112.679 289.683 112.679C286.58 112.679 284.205 113.249 282.559 114.389C280.976 115.529 280.184 117.175 280.184 119.328H268.026C268.026 115.719 268.944 112.584 270.78 109.924C272.617 107.265 275.213 105.207 278.569 103.75C281.989 102.294 285.947 101.566 290.443 101.566C295.065 101.566 298.96 102.389 302.126 104.035C305.355 105.682 307.793 108.088 309.44 111.254C311.149 114.42 312.004 118.283 312.004 122.843V150.578H299.086L298.136 144.309C297.376 146.462 295.572 148.267 292.722 149.723C289.936 151.117 286.77 151.813 283.224 151.813ZM288.353 140.985C291.139 140.985 293.419 140.32 295.192 138.99C296.965 137.597 297.851 135.539 297.851 132.816V130.251L290.443 130.916C287.276 131.17 285.028 131.708 283.699 132.531C282.432 133.291 281.799 134.431 281.799 135.951C281.799 137.66 282.337 138.927 283.414 139.75C284.49 140.573 286.136 140.985 288.353 140.985ZM342.823 150.578H328.195V103.085H341.968L342.918 108.025C344.374 105.998 346.369 104.415 348.902 103.275C351.498 102.136 354.348 101.566 357.451 101.566C363.086 101.566 367.456 103.307 370.559 106.79C373.725 110.209 375.308 115.022 375.308 121.228V150.578H360.68V124.742C360.68 121.766 359.92 119.391 358.4 117.618C356.881 115.782 354.854 114.864 352.321 114.864C349.408 114.864 347.097 115.75 345.387 117.523C343.678 119.233 342.823 121.576 342.823 124.552V150.578ZM389.123 125.977C389.123 121.164 390.073 116.922 391.973 113.249C393.936 109.576 396.627 106.695 400.047 104.605C403.529 102.516 407.487 101.471 411.92 101.471C415.656 101.471 418.854 102.231 421.513 103.75C424.236 105.27 426.104 107.265 427.117 109.734L425.693 110.684L426.833 103.085H440.605V147.539C440.605 153.175 439.561 158.019 437.471 162.072C435.381 166.188 432.405 169.322 428.542 171.475C424.679 173.692 420.025 174.8 414.579 174.8C407.297 174.8 401.376 172.837 396.817 168.911C392.258 165.048 389.63 159.76 388.933 153.048H403.751C403.878 155.708 404.891 157.766 406.79 159.222C408.69 160.742 411.255 161.502 414.484 161.502C418.03 161.502 420.817 160.52 422.843 158.557C424.933 156.594 425.978 153.935 425.978 150.578V140.51L427.592 141.745C426.579 144.214 424.616 146.209 421.703 147.729C418.79 149.249 415.434 150.008 411.635 150.008C407.202 150.008 403.276 148.995 399.857 146.969C396.5 144.943 393.872 142.125 391.973 138.515C390.073 134.906 389.123 130.726 389.123 125.977ZM403.846 125.597C403.846 127.877 404.321 129.903 405.271 131.676C406.221 133.386 407.519 134.747 409.165 135.761C410.812 136.774 412.711 137.28 414.864 137.28C417.081 137.28 419.012 136.805 420.658 135.856C422.368 134.842 423.666 133.481 424.553 131.771C425.503 129.998 425.978 127.94 425.978 125.597C425.978 123.254 425.503 121.259 424.553 119.613C423.666 117.903 422.368 116.573 420.658 115.624C419.012 114.674 417.049 114.199 414.769 114.199C412.616 114.199 410.717 114.674 409.07 115.624C407.424 116.573 406.126 117.903 405.176 119.613C404.289 121.323 403.846 123.317 403.846 125.597ZM471.933 150.578H457.305V78.9591H471.933V150.578ZM510.643 151.813C505.893 151.813 501.651 150.737 497.915 148.584C494.242 146.431 491.329 143.486 489.176 139.75C487.086 135.951 486.041 131.613 486.041 126.737C486.041 121.798 487.055 117.46 489.081 113.724C491.171 109.924 494.052 106.948 497.725 104.795C501.397 102.642 505.608 101.566 510.358 101.566C515.36 101.566 519.666 102.611 523.276 104.7C526.885 106.727 529.671 109.639 531.635 113.439C533.598 117.175 534.579 121.639 534.579 126.832V130.536L493.735 130.726L493.925 121.703H520.046C520.046 119.17 519.191 117.175 517.482 115.719C515.772 114.199 513.429 113.439 510.453 113.439C507.983 113.439 505.957 113.914 504.374 114.864C502.854 115.814 501.714 117.302 500.954 119.328C500.194 121.291 499.814 123.824 499.814 126.927C499.814 131.36 500.701 134.652 502.474 136.805C504.31 138.895 507.128 139.94 510.928 139.94C513.714 139.94 516.025 139.465 517.862 138.515C519.698 137.565 520.869 136.236 521.376 134.526H534.769C533.946 139.782 531.35 143.993 526.98 147.159C522.611 150.262 517.165 151.813 510.643 151.813Z'\n\n/** Brand gradient + clip shared by the icon and the full lockup. Static ids are\n * fine: every instance defines the identical gradient, so a duplicate id in the\n * document resolves to an identical paint. */\nfunction KnotDefs() {\n return (\n <defs>\n <linearGradient id=\"tangleKnotA\" x1=\"36.79\" y1=\"58.78\" x2=\"145.99\" y2=\"183.59\" gradientUnits=\"userSpaceOnUse\">\n <stop stopColor=\"#8E59FF\" />\n <stop offset=\"1\" stopColor=\"#6888F9\" />\n </linearGradient>\n <linearGradient id=\"tangleKnotB\" x1=\"36.78\" y1=\"169.38\" x2=\"145.99\" y2=\"44.57\" gradientUnits=\"userSpaceOnUse\">\n <stop stopColor=\"#8E59FF\" />\n <stop offset=\"1\" stopColor=\"#6888F9\" />\n </linearGradient>\n <clipPath id=\"tangleKnotClip\">\n <rect width=\"126.648\" height=\"144.74\" fill=\"white\" transform=\"translate(170.74 50.7545) rotate(90)\" />\n </clipPath>\n </defs>\n )\n}\n\nfunction KnotPaths() {\n return (\n <g clipPath=\"url(#tangleKnotClip)\">\n <path d={KNOT_PATH_A} fill=\"url(#tangleKnotA)\" />\n <path opacity=\"0.8\" d={KNOT_PATH_B} fill=\"url(#tangleKnotB)\" />\n </g>\n )\n}\n\n/** Icon-only Tangle knot, brand gradient, theme-independent. `size` is the\n * rendered square in px. */\nexport function TangleKnot({ size = 24, className }: { size?: number; className?: string }) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"22 46 152 136\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={className}\n role=\"img\"\n aria-label=\"Tangle\"\n >\n <KnotPaths />\n <KnotDefs />\n </svg>\n )\n}\n\nconst WORDMARK_HEIGHTS: Record<NonNullable<LogoProps['size']>, number> = { sm: 16, md: 20, lg: 28, xl: 40 }\nconst LOCKUP_RATIO = 564 / 228\n\n/** Full Tangle lockup (knot + wordmark) or, with `iconOnly`, just the knot. The\n * wordmark paints with `currentColor` so it inherits the surrounding text color\n * and adapts to light/dark automatically. */\nexport function Logo({ variant = 'sandbox', size = 'md', className, iconOnly = false }: LogoProps) {\n void variant\n const height = WORDMARK_HEIGHTS[size]\n if (iconOnly) return <TangleKnot size={height} className={className} />\n return (\n <svg\n width={Math.round(height * LOCKUP_RATIO)}\n height={height}\n viewBox=\"0 0 564 228\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={className}\n role=\"img\"\n aria-label=\"Tangle\"\n >\n <KnotPaths />\n <path d={WORDMARK_PATH} fill=\"currentColor\" />\n <KnotDefs />\n </svg>\n )\n}\n\n/** Define properties for a brand header including optional title, children, and CSS class name */\nexport interface BrandHeaderProps {\n /** Product name rendered next to the knot. Omit for a mark-only header. */\n title?: string\n /** Right-aligned slot for nav, actions, theme toggles. */\n children?: ReactNode\n className?: string\n}\n\n/**\n * Shared app-shell header: icon-only Tangle knot + optional product title on\n * the left, caller-supplied nav/actions on the right. Token-styled only.\n */\nexport function BrandHeader({ title, children, className }: BrandHeaderProps) {\n return (\n <header\n className={`flex shrink-0 items-center gap-3 border-b border-border bg-card px-4 py-2${\n className ? ` ${className}` : ''\n }`}\n >\n <span className=\"flex items-center gap-2\">\n <TangleKnot size={24} className=\"shrink-0\" />\n {title ? <span className=\"text-sm font-semibold text-foreground\">{title}</span> : null}\n </span>\n {children ? <div className=\"flex flex-1 items-center justify-end gap-1\">{children}</div> : null}\n </header>\n )\n}\n"],"mappings":";AA6CM,SACE,KADF;AAbN,IAAM,cACJ;AACF,IAAM,cACJ;AACF,IAAM,gBACJ;AAKF,SAAS,WAAW;AAClB,SACE,qBAAC,UACC;AAAA,yBAAC,oBAAe,IAAG,eAAc,IAAG,SAAQ,IAAG,SAAQ,IAAG,UAAS,IAAG,UAAS,eAAc,kBAC3F;AAAA,0BAAC,UAAK,WAAU,WAAU;AAAA,MAC1B,oBAAC,UAAK,QAAO,KAAI,WAAU,WAAU;AAAA,OACvC;AAAA,IACA,qBAAC,oBAAe,IAAG,eAAc,IAAG,SAAQ,IAAG,UAAS,IAAG,UAAS,IAAG,SAAQ,eAAc,kBAC3F;AAAA,0BAAC,UAAK,WAAU,WAAU;AAAA,MAC1B,oBAAC,UAAK,QAAO,KAAI,WAAU,WAAU;AAAA,OACvC;AAAA,IACA,oBAAC,cAAS,IAAG,kBACX,8BAAC,UAAK,OAAM,WAAU,QAAO,UAAS,MAAK,SAAQ,WAAU,wCAAuC,GACtG;AAAA,KACF;AAEJ;AAEA,SAAS,YAAY;AACnB,SACE,qBAAC,OAAE,UAAS,wBACV;AAAA,wBAAC,UAAK,GAAG,aAAa,MAAK,qBAAoB;AAAA,IAC/C,oBAAC,UAAK,SAAQ,OAAM,GAAG,aAAa,MAAK,qBAAoB;AAAA,KAC/D;AAEJ;AAIO,SAAS,WAAW,EAAE,OAAO,IAAI,UAAU,GAA0C;AAC1F,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAM;AAAA,MACN;AAAA,MACA,MAAK;AAAA,MACL,cAAW;AAAA,MAEX;AAAA,4BAAC,aAAU;AAAA,QACX,oBAAC,YAAS;AAAA;AAAA;AAAA,EACZ;AAEJ;AAEA,IAAM,mBAAmE,EAAE,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG;AAC1G,IAAM,eAAe,MAAM;AAKpB,SAAS,KAAK,EAAE,UAAU,WAAW,OAAO,MAAM,WAAW,WAAW,MAAM,GAAc;AACjG,OAAK;AACL,QAAM,SAAS,iBAAiB,IAAI;AACpC,MAAI,SAAU,QAAO,oBAAC,cAAW,MAAM,QAAQ,WAAsB;AACrE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,KAAK,MAAM,SAAS,YAAY;AAAA,MACvC;AAAA,MACA,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAM;AAAA,MACN;AAAA,MACA,MAAK;AAAA,MACL,cAAW;AAAA,MAEX;AAAA,4BAAC,aAAU;AAAA,QACX,oBAAC,UAAK,GAAG,eAAe,MAAK,gBAAe;AAAA,QAC5C,oBAAC,YAAS;AAAA;AAAA;AAAA,EACZ;AAEJ;AAeO,SAAS,YAAY,EAAE,OAAO,UAAU,UAAU,GAAqB;AAC5E,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,4EACT,YAAY,IAAI,SAAS,KAAK,EAChC;AAAA,MAEA;AAAA,6BAAC,UAAK,WAAU,2BACd;AAAA,8BAAC,cAAW,MAAM,IAAI,WAAU,YAAW;AAAA,UAC1C,QAAQ,oBAAC,UAAK,WAAU,yCAAyC,iBAAM,IAAU;AAAA,WACpF;AAAA,QACC,WAAW,oBAAC,SAAI,WAAU,8CAA8C,UAAS,IAAS;AAAA;AAAA;AAAA,EAC7F;AAEJ;","names":[]}
|
|
@@ -105,6 +105,7 @@ type FetchLike = (url: string, init?: {
|
|
|
105
105
|
get(name: string): string | null;
|
|
106
106
|
};
|
|
107
107
|
}>;
|
|
108
|
+
/** Define options for extracting brand kit data including HTML input, fetch method, timeout, and list limits */
|
|
108
109
|
interface ExtractBrandKitOptions {
|
|
109
110
|
/** Raw HTML for the page. When supplied, no network fetch happens — used by
|
|
110
111
|
* tests and by callers that already hold the HTML. */
|
|
@@ -164,6 +165,7 @@ declare function extractBrandKit(url: string, options?: ExtractBrandKitOptions):
|
|
|
164
165
|
|
|
165
166
|
/** Relative luminance (0..1) of an #rrggbb(aa) hex — for light/dark sorting. */
|
|
166
167
|
declare function luminance(hex: string): number;
|
|
168
|
+
/** Define a color palette with background, surface, text, and accent colors for UI elements */
|
|
167
169
|
interface DecidedPalette {
|
|
168
170
|
/** Lightest neutral — page background. */
|
|
169
171
|
background?: string;
|
|
@@ -184,6 +186,7 @@ interface DecidedPalette {
|
|
|
184
186
|
* the kit actually contained a color that fits.
|
|
185
187
|
*/
|
|
186
188
|
declare function decidePalette(palette: BrandColor[]): DecidedPalette;
|
|
189
|
+
/** Define font selections for display and body text with optional BrandFont properties */
|
|
187
190
|
interface DecidedFonts {
|
|
188
191
|
display?: BrandFont;
|
|
189
192
|
body?: BrandFont;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/brand-extraction/extract.ts","../../src/brand-extraction/map.ts"],"sourcesContent":["/**\n * Brand-kit extraction engine.\n *\n * Given a website URL (or raw HTML), parse the page and pull a typed BrandKit:\n * logo candidates, color palette, fonts, and prominent images. Parsing is\n * regex-based on purpose — this runs on Cloudflare Workers and other edge\n * runtimes where DOM libraries (jsdom/cheerio) are unavailable, and the page\n * structures we read (link tags, meta tags, CSS custom properties, font-family\n * declarations) are flat enough that a DOM buys nothing.\n *\n * Degrades gracefully: a missing favicon, no CSS tokens, or an image-only page\n * each narrow the kit rather than failing it. The ONLY hard failures are a bad\n * input (no html and no fetch) and a fetch error — both returned as a typed\n * `{ succeeded: false }` outcome so callers never mistake an empty kit for a\n * real one.\n */\n\nimport type {\n BrandColor,\n BrandExtractionResult,\n BrandFont,\n BrandImage,\n BrandKit,\n BrandLogoCandidate,\n ExtractBrandKitOptions,\n FetchLike,\n} from './types'\n\nconst DEFAULT_TIMEOUT_MS = 15000\nconst DEFAULT_MAX_PER_LIST = 12\n\n// ── URL helpers ──────────────────────────────────────────────────────────────\n\n/** Normalize a user-supplied site URL: add https:// when scheme-less, validate. */\nexport function normalizeSiteUrl(raw: string): string | null {\n const trimmed = raw.trim()\n if (!trimmed) return null\n // A non-http(s) scheme is an explicit reject — don't paper over it by\n // prepending https:// (that would turn \"ftp://x\" into host \"ftp\").\n if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed) && !/^https?:\\/\\//i.test(trimmed)) return null\n const withScheme = /^https?:\\/\\//i.test(trimmed) ? trimmed : `https://${trimmed}`\n try {\n const u = new URL(withScheme)\n if (u.protocol !== 'http:' && u.protocol !== 'https:') return null\n return u.toString()\n } catch {\n return null\n }\n}\n\n/** Resolve a possibly-relative href against the page URL. Returns null for\n * data: URIs and unresolvable values — we want servable http(s) URLs only. */\nfunction absolutize(href: string, base: string): string | null {\n const v = href.trim()\n if (!v || v.startsWith('data:') || v.startsWith('javascript:')) return null\n try {\n const u = new URL(v, base)\n if (u.protocol !== 'http:' && u.protocol !== 'https:') return null\n return u.toString()\n } catch {\n return null\n }\n}\n\n// ── Attribute parsing ────────────────────────────────────────────────────────\n\n/** Pull all `<tag ...>` open-tags from html (case-insensitive). */\nfunction matchTags(html: string, tag: string): string[] {\n const re = new RegExp(`<${tag}\\\\b[^>]*>`, 'gi')\n return html.match(re) ?? []\n}\n\n/** Read an attribute value from a single tag string. Handles quoted and\n * unquoted values. Returns undefined when absent. */\nfunction attr(tag: string, name: string): string | undefined {\n const quoted = new RegExp(`\\\\b${name}\\\\s*=\\\\s*[\"']([^\"']*)[\"']`, 'i').exec(tag)\n if (quoted) return decodeEntities(quoted[1] ?? '')\n const bare = new RegExp(`\\\\b${name}\\\\s*=\\\\s*([^\\\\s\"'>]+)`, 'i').exec(tag)\n return bare ? decodeEntities(bare[1] ?? '') : undefined\n}\n\nfunction decodeEntities(s: string): string {\n return s\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(///gi, '/')\n}\n\n// ── Name / description ───────────────────────────────────────────────────────\n\nfunction extractName(html: string): string | undefined {\n for (const tag of matchTags(html, 'meta')) {\n const prop = (attr(tag, 'property') ?? attr(tag, 'name'))?.toLowerCase()\n if (prop === 'og:site_name') {\n const c = attr(tag, 'content')?.trim()\n if (c) return c\n }\n }\n const title = /<title[^>]*>([\\s\\S]*?)<\\/title>/i.exec(html)?.[1]\n if (title) {\n // \"Acme — the best widget\" → \"Acme\". Split on common separators, take head.\n const head = (decodeEntities(title).split(/\\s+[|–—\\-:·]\\s+/)[0] ?? '').trim()\n if (head) return head\n }\n return undefined\n}\n\nfunction extractDescription(html: string): string | undefined {\n for (const tag of matchTags(html, 'meta')) {\n const prop = (attr(tag, 'property') ?? attr(tag, 'name'))?.toLowerCase()\n if (prop === 'description' || prop === 'og:description') {\n const c = attr(tag, 'content')?.trim()\n if (c) return c\n }\n }\n return undefined\n}\n\n// ── Logos ────────────────────────────────────────────────────────────────────\n\nconst MIME_BY_EXT: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n ico: 'image/x-icon',\n}\n\nfunction mimeFromUrl(url: string): string | undefined {\n const ext = new URL(url).pathname.split('.').pop()?.toLowerCase()\n return ext ? MIME_BY_EXT[ext] : undefined\n}\n\nfunction parseSizes(sizes: string | undefined): { width?: number; height?: number } {\n if (!sizes) return {}\n const m = /(\\d+)\\s*[x×]\\s*(\\d+)/i.exec(sizes)\n if (!m) return {}\n return { width: Number(m[1]), height: Number(m[2]) }\n}\n\nfunction extractLogos(html: string, base: string): BrandLogoCandidate[] {\n const out: BrandLogoCandidate[] = []\n const seen = new Set<string>()\n const push = (c: BrandLogoCandidate) => {\n if (seen.has(c.url)) return\n seen.add(c.url)\n out.push(c)\n }\n\n // link rel icons / apple-touch-icon\n for (const tag of matchTags(html, 'link')) {\n const rel = attr(tag, 'rel')?.toLowerCase() ?? ''\n const href = attr(tag, 'href')\n if (!href) continue\n const url = absolutize(href, base)\n if (!url) continue\n const { width, height } = parseSizes(attr(tag, 'sizes'))\n if (rel.includes('apple-touch-icon')) {\n push({ url, source: 'apple-touch-icon', confidence: 0.7, width, height, mimeType: mimeFromUrl(url) })\n } else if (rel.split(/\\s+/).includes('icon') || rel.includes('shortcut icon')) {\n push({ url, source: 'favicon', confidence: 0.5, width, height, mimeType: mimeFromUrl(url) })\n }\n }\n\n // og:image (often shows the logo in context — moderate confidence)\n for (const tag of matchTags(html, 'meta')) {\n const prop = (attr(tag, 'property') ?? attr(tag, 'name'))?.toLowerCase()\n if (prop === 'og:image' || prop === 'og:image:url') {\n const href = attr(tag, 'content')\n const url = href ? absolutize(href, base) : null\n if (url) push({ url, source: 'og:image', confidence: 0.55, mimeType: mimeFromUrl(url) })\n }\n }\n\n // <img> whose src/class/alt/id mentions \"logo\" — the strongest in-page signal\n for (const tag of matchTags(html, 'img')) {\n const src = attr(tag, 'src') ?? attr(tag, 'data-src')\n if (!src) continue\n const alt = attr(tag, 'alt')\n const cls = attr(tag, 'class') ?? ''\n const id = attr(tag, 'id') ?? ''\n const looksLikeLogo = /logo|brand|wordmark/i.test(`${src} ${alt ?? ''} ${cls} ${id}`)\n if (!looksLikeLogo) continue\n const url = absolutize(src, base)\n if (!url) continue\n const w = attr(tag, 'width')\n const h = attr(tag, 'height')\n push({\n url,\n source: 'img-logo',\n confidence: 0.85,\n alt,\n width: w ? Number(w) || undefined : undefined,\n height: h ? Number(h) || undefined : undefined,\n mimeType: mimeFromUrl(url),\n })\n }\n\n // No favicon link tag at all? Fall back to the conventional /favicon.ico —\n // it almost always exists. Lowest confidence.\n if (!out.some((l) => l.source === 'favicon' || l.source === 'apple-touch-icon')) {\n const fav = absolutize('/favicon.ico', base)\n if (fav) push({ url: fav, source: 'favicon', confidence: 0.3, mimeType: 'image/x-icon' })\n }\n\n return out.sort((a, b) => b.confidence - a.confidence)\n}\n\n// ── Colors ───────────────────────────────────────────────────────────────────\n\n/** Normalize any CSS color literal to #rrggbb / #rrggbbaa hex, or null. */\nexport function normalizeColor(raw: string): string | null {\n const v = raw.trim().toLowerCase()\n // #rgb / #rgba / #rrggbb / #rrggbbaa\n const hex = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.exec(v)\n if (hex) {\n const h = hex[1] ?? ''\n // Expand 3/4-digit shorthand by doubling each nibble.\n if (h.length === 3 || h.length === 4) {\n return `#${h.split('').map((c) => c + c).join('')}`\n }\n return `#${h}`\n }\n // rgb()/rgba()\n const rgb = /^rgba?\\(\\s*([\\d.]+)[\\s,]+([\\d.]+)[\\s,]+([\\d.]+)(?:[\\s,/]+([\\d.%]+))?\\s*\\)$/.exec(v)\n if (rgb) {\n const to255 = (n: string | undefined) => Math.max(0, Math.min(255, Math.round(Number(n))))\n const r = to255(rgb[1]).toString(16).padStart(2, '0')\n const g = to255(rgb[2]).toString(16).padStart(2, '0')\n const b = to255(rgb[3]).toString(16).padStart(2, '0')\n let a = ''\n if (rgb[4] !== undefined) {\n const av = rgb[4].endsWith('%') ? Number(rgb[4].slice(0, -1)) / 100 : Number(rgb[4])\n const ai = Math.max(0, Math.min(255, Math.round(av * 255)))\n if (ai < 255) a = ai.toString(16).padStart(2, '0')\n }\n return `#${r}${g}${b}${a}`\n }\n return null\n}\n\nconst COLOR_LITERAL_RE = /#[0-9a-fA-F]{3,8}\\b|rgba?\\([^)]*\\)/g\nconst ROOT_VAR_RE = /(--[a-z0-9-]*(?:color|colour|bg|background|accent|brand|primary|secondary|surface|text|fg|ink)[a-z0-9-]*)\\s*:\\s*([^;}{]+)/gi\n\nfunction extractPalette(html: string): BrandColor[] {\n const byHex = new Map<string, BrandColor>()\n const bump = (hex: string, fromToken: boolean, tokenName?: string) => {\n const existing = byHex.get(hex)\n if (existing) {\n existing.occurrences += 1\n if (fromToken && !existing.fromToken) {\n existing.fromToken = true\n existing.tokenName = tokenName\n }\n } else {\n byHex.set(hex, { hex, occurrences: 1, fromToken, ...(tokenName ? { tokenName } : {}) })\n }\n }\n\n // CSS custom properties — highest-fidelity design tokens.\n for (const m of html.matchAll(ROOT_VAR_RE)) {\n const tokenName = m[1]\n const value = m[2]\n if (!value) continue\n const lit = value.match(COLOR_LITERAL_RE)?.[0]\n if (!lit) continue\n const hex = normalizeColor(lit)\n if (hex) bump(hex, true, tokenName)\n }\n\n // All other color literals across the document (inline styles, <style>).\n for (const m of html.matchAll(COLOR_LITERAL_RE)) {\n const hex = normalizeColor(m[0])\n if (hex) bump(hex, false)\n }\n\n // Rank: token-sourced first, then by popularity. Drop pure white/black noise\n // to the back so a real brand color leads.\n const isNeutral = (h: string) => /^#(0{6}|f{6})(ff)?$/i.test(h)\n return [...byHex.values()].sort((a, b) => {\n if (a.fromToken !== b.fromToken) return a.fromToken ? -1 : 1\n const an = isNeutral(a.hex) ? 1 : 0\n const bn = isNeutral(b.hex) ? 1 : 0\n if (an !== bn) return an - bn\n return b.occurrences - a.occurrences\n })\n}\n\n// ── Fonts ────────────────────────────────────────────────────────────────────\n\nconst GENERIC_FAMILIES = new Set([\n 'serif', 'sans-serif', 'monospace', 'cursive', 'fantasy', 'system-ui',\n 'ui-sans-serif', 'ui-serif', 'ui-monospace', 'ui-rounded', 'inherit', 'initial', 'unset',\n])\n\n/** font-family declarations, with the selector chunk preceding them for role\n * inference. Captures the selector text in group 1, the stack in group 2. */\nconst FONT_DECL_RE = /([^{}]*)\\{[^{}]*font-family\\s*:\\s*([^;}{]+)[;}]/gi\n\nfunction parseFontStack(raw: string | undefined): string[] {\n if (!raw) return []\n return raw\n .split(',')\n .map((s) => s.trim().replace(/^[\"']|[\"']$/g, ''))\n .filter(Boolean)\n}\n\nfunction roleFromSelector(selector: string): 'display' | 'body' | 'unknown' {\n const s = selector.toLowerCase()\n if (/\\b(h[1-3]|\\.h[1-3]|heading|title|display|hero)\\b/.test(s)) return 'display'\n if (/\\b(body|p|html|\\.text|\\.content|root|:root|\\*)\\b/.test(s)) return 'body'\n return 'unknown'\n}\n\nfunction extractFonts(html: string): BrandFont[] {\n // Restrict to <style> blocks + the whole doc; inline style=\"\" attributes are\n // included because the regex matches any `{...font-family...}` chunk, but we\n // also scan style attributes explicitly below.\n const byFamily = new Map<string, BrandFont>()\n const consider = (family: string, stack: string[], role: BrandFont['role']) => {\n const key = family.toLowerCase()\n if (!family || GENERIC_FAMILIES.has(key)) return\n const existing = byFamily.get(key)\n if (existing) {\n existing.occurrences += 1\n if (existing.role === 'unknown' && role !== 'unknown') existing.role = role\n } else {\n byFamily.set(key, { family, stack, role, occurrences: 1 })\n }\n }\n\n for (const m of html.matchAll(FONT_DECL_RE)) {\n const selector = m[1] ?? ''\n const stack = parseFontStack(m[2])\n const primary = stack[0]\n if (!primary) continue\n consider(primary, stack, roleFromSelector(selector))\n }\n\n // Bare `font-family:` declarations inside inline style attributes and tokens.\n const BARE_RE = /font-family\\s*:\\s*([^;\"'}{]+)/gi\n for (const m of html.matchAll(BARE_RE)) {\n const stack = parseFontStack(m[1])\n const primary = stack[0]\n if (!primary) continue\n consider(primary, stack, 'unknown')\n }\n\n // Google Fonts <link href=\"...family=Inter:wght@400...\"> — strong signal.\n for (const tag of matchTags(html, 'link')) {\n const href = attr(tag, 'href') ?? ''\n if (!/fonts\\.googleapis\\.com/i.test(href)) continue\n for (const fam of href.matchAll(/family=([^:&]+)/gi)) {\n const captured = fam[1]\n if (!captured) continue\n const family = decodeURIComponent(captured.replace(/\\+/g, ' ')).trim()\n consider(family, [family], 'display')\n }\n }\n\n return [...byFamily.values()].sort((a, b) => {\n const rank = (r: BrandFont['role']) => (r === 'display' ? 0 : r === 'body' ? 1 : 2)\n const rr = rank(a.role) - rank(b.role)\n if (rr !== 0) return rr\n return b.occurrences - a.occurrences\n })\n}\n\n// ── Images ───────────────────────────────────────────────────────────────────\n\nfunction extractImages(html: string, base: string): BrandImage[] {\n const out: BrandImage[] = []\n const seen = new Set<string>()\n const push = (img: BrandImage) => {\n if (seen.has(img.url)) return\n seen.add(img.url)\n out.push(img)\n }\n\n for (const tag of matchTags(html, 'meta')) {\n const prop = (attr(tag, 'property') ?? attr(tag, 'name'))?.toLowerCase()\n const href = attr(tag, 'content')\n const url = href ? absolutize(href, base) : null\n if (!url) continue\n if (prop === 'og:image' || prop === 'og:image:url') push({ url, source: 'og:image' })\n else if (prop === 'twitter:image' || prop === 'twitter:image:src') push({ url, source: 'twitter:image' })\n }\n\n for (const tag of matchTags(html, 'img')) {\n const src = attr(tag, 'src') ?? attr(tag, 'data-src')\n if (!src) continue\n const url = absolutize(src, base)\n if (!url) continue\n const cls = `${attr(tag, 'class') ?? ''} ${attr(tag, 'id') ?? ''}`\n // Skip obvious logos/icons — those go in the logos list, not images.\n if (/logo|icon|favicon|wordmark/i.test(`${url} ${cls}`)) continue\n const isHero = /hero|banner|cover|feature|splash/i.test(cls)\n const w = attr(tag, 'width')\n const h = attr(tag, 'height')\n push({\n url,\n source: isHero ? 'img-hero' : 'img-content',\n alt: attr(tag, 'alt'),\n width: w ? Number(w) || undefined : undefined,\n height: h ? Number(h) || undefined : undefined,\n })\n }\n\n const rank = (s: BrandImage['source']) =>\n s === 'og:image' ? 0 : s === 'twitter:image' ? 1 : s === 'img-hero' ? 2 : 3\n return out.sort((a, b) => rank(a.source) - rank(b.source))\n}\n\n// ── Public API ───────────────────────────────────────────────────────────────\n\n/** Parse already-fetched HTML into a BrandKit. Pure — no network. Exposed so\n * callers that hold the HTML (or want to combine multiple pages) can reuse the\n * parsing without re-fetching. */\nexport function parseBrandKit(html: string, sourceUrl: string, maxPerList = DEFAULT_MAX_PER_LIST): BrandKit {\n const logos = extractLogos(html, sourceUrl).slice(0, maxPerList)\n const palette = extractPalette(html).slice(0, maxPerList)\n const fonts = extractFonts(html).slice(0, maxPerList)\n const images = extractImages(html, sourceUrl).slice(0, maxPerList)\n const name = extractName(html)\n const description = extractDescription(html)\n\n return {\n sourceUrl,\n ...(name ? { name } : {}),\n ...(description ? { description } : {}),\n logos,\n palette,\n fonts,\n images,\n extractedFrom: [sourceUrl],\n }\n}\n\n/**\n * Fetch a website (or use supplied HTML) and extract its BrandKit.\n *\n * Returns a typed outcome — callers MUST check `succeeded`. A fetch failure or\n * empty input is a real, surfaced error, never an empty kit masquerading as a\n * result. Parsing itself never throws: a malformed page yields a sparse kit\n * with warnings, which is information, not failure.\n */\nexport async function extractBrandKit(\n url: string,\n options: ExtractBrandKitOptions = {},\n): Promise<BrandExtractionResult> {\n const { html: providedHtml, fetchImpl, timeoutMs = DEFAULT_TIMEOUT_MS, maxPerList = DEFAULT_MAX_PER_LIST } = options\n const warnings: string[] = []\n\n const sourceUrl = normalizeSiteUrl(url)\n if (!sourceUrl) {\n return { succeeded: false, error: `Not a valid http(s) URL: ${JSON.stringify(url)}`, stage: 'input' }\n }\n\n let html = providedHtml\n if (html === undefined) {\n const doFetch: FetchLike | undefined =\n fetchImpl ?? (typeof globalThis.fetch === 'function'\n ? (u, init) => globalThis.fetch(u, init as RequestInit)\n : undefined)\n if (!doFetch) {\n return { succeeded: false, error: 'No html provided and no fetch implementation available', stage: 'input' }\n }\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), timeoutMs)\n try {\n const res = await doFetch(sourceUrl, {\n signal: controller.signal,\n headers: { 'user-agent': 'TangleBrandExtractor/1.0 (+https://tangle.tools)' },\n })\n if (!res.ok) {\n return { succeeded: false, error: `Fetch failed: HTTP ${res.status} for ${sourceUrl}`, stage: 'fetch' }\n }\n html = await res.text()\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err)\n return { succeeded: false, error: `Fetch error for ${sourceUrl}: ${reason}`, stage: 'fetch' }\n } finally {\n clearTimeout(timer)\n }\n }\n\n if (!html.trim()) {\n return { succeeded: false, error: `Empty document for ${sourceUrl}`, stage: 'parse' }\n }\n\n const kit = parseBrandKit(html, sourceUrl, maxPerList)\n\n if (kit.logos.length === 0) warnings.push('No logo candidates found.')\n if (kit.palette.length === 0) warnings.push('No colors extracted — page has no inline CSS or design tokens.')\n if (kit.fonts.length === 0) warnings.push('No custom fonts found — site likely uses system defaults.')\n if (kit.images.length === 0) warnings.push('No prominent images found.')\n\n return { succeeded: true, kit, warnings }\n}\n","/**\n * Pure mapping helpers from an extracted BrandKit onto consumable shapes.\n *\n * Extraction yields ranked candidate lists; products need decided roles\n * (background vs accent, display vs body). These helpers make the obvious,\n * defensible default choice and expose the reasoning so a confirmation UI can\n * show \"we picked X — change it?\". They NEVER invent a value: when a role can't\n * be filled from the kit, it is omitted, and the caller decides the fallback.\n */\n\nimport type { BrandColor, BrandFont, BrandKit } from './types'\n\n/** Relative luminance (0..1) of an #rrggbb(aa) hex — for light/dark sorting. */\nexport function luminance(hex: string): number {\n const h = hex.replace('#', '').slice(0, 6)\n const r = parseInt(h.slice(0, 2), 16) / 255\n const g = parseInt(h.slice(2, 4), 16) / 255\n const b = parseInt(h.slice(4, 6), 16) / 255\n const lin = (c: number) => (c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4)\n return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b)\n}\n\nfunction isGreyish(hex: string): boolean {\n const h = hex.replace('#', '').slice(0, 6)\n const r = parseInt(h.slice(0, 2), 16)\n const g = parseInt(h.slice(2, 4), 16)\n const b = parseInt(h.slice(4, 6), 16)\n const max = Math.max(r, g, b)\n const min = Math.min(r, g, b)\n return max - min < 18\n}\n\nexport interface DecidedPalette {\n /** Lightest neutral — page background. */\n background?: string\n /** A raised neutral one step from background. */\n surface?: string\n /** Darkest readable color — primary text. */\n textPrimary?: string\n /** Mid-tone neutral — secondary text. */\n textSecondary?: string\n /** Most saturated / popular brand color — accent. */\n accent?: string\n /** Readable text color to sit on the accent (black or white by contrast). */\n accentText?: string\n}\n\n/**\n * Assign palette roles from the ranked colors. Heuristic, not authoritative —\n * a confirmation step should let the user correct it. Roles only appear when\n * the kit actually contained a color that fits.\n */\nexport function decidePalette(palette: BrandColor[]): DecidedPalette {\n if (palette.length === 0) return {}\n const hexes = palette.map((c) => c.hex)\n const greys = hexes.filter(isGreyish).sort((a, b) => luminance(b) - luminance(a))\n const colored = hexes.filter((h) => !isGreyish(h))\n\n // Accent: the top-ranked non-grey (token-first, popularity-first) color.\n const accent = colored[0]\n // Background: lightest grey (or lightest overall when no greys).\n const sortedLight = [...hexes].sort((a, b) => luminance(b) - luminance(a))\n const background = greys[0] ?? sortedLight[0]\n // Surface: next grey under background, else second-lightest.\n const surface = greys[1] ?? sortedLight.find((h) => h !== background)\n // Text primary: darkest color overall.\n const textPrimary = [...hexes].sort((a, b) => luminance(a) - luminance(b))[0]\n // Text secondary: a mid-luminance grey distinct from primary/background.\n const textSecondary = greys.find((h) => h !== background && h !== surface && h !== textPrimary)\n\n const result: DecidedPalette = {}\n if (background) result.background = background\n if (surface) result.surface = surface\n if (textPrimary) result.textPrimary = textPrimary\n if (textSecondary) result.textSecondary = textSecondary\n if (accent) {\n result.accent = accent\n result.accentText = luminance(accent) > 0.45 ? '#000000' : '#ffffff'\n }\n return result\n}\n\nexport interface DecidedFonts {\n display?: BrandFont\n body?: BrandFont\n}\n\n/** Pick a display and body font from the ranked list. When only one usable\n * font exists it fills both roles — a single-typeface brand is valid. */\nexport function decideFonts(fonts: BrandFont[]): DecidedFonts {\n if (fonts.length === 0) return {}\n const display = fonts.find((f) => f.role === 'display') ?? fonts[0]\n const body = fonts.find((f) => f.role === 'body') ?? fonts.find((f) => f !== display) ?? display\n return { display, body }\n}\n\n/** Everything a confirmation step needs from a kit, with roles decided. */\nexport interface DecidedBrandKit {\n name?: string\n description?: string\n sourceUrl: string\n palette: DecidedPalette\n fonts: DecidedFonts\n /** Best logo URL, when any candidate was found. */\n primaryLogoUrl?: string\n /** All logo URLs, ranked. */\n logoUrls: string[]\n /** Prominent image URLs, ranked. */\n imageUrls: string[]\n extractedFrom: string[]\n}\n\n/** Collapse a raw BrandKit into decided roles — the shape a product persists. */\nexport function decideBrandKit(kit: BrandKit): DecidedBrandKit {\n const palette = decidePalette(kit.palette)\n const fonts = decideFonts(kit.fonts)\n const logoUrls = kit.logos.map((l) => l.url)\n const result: DecidedBrandKit = {\n sourceUrl: kit.sourceUrl,\n palette,\n fonts,\n logoUrls,\n imageUrls: kit.images.map((i) => i.url),\n extractedFrom: kit.extractedFrom,\n }\n if (kit.name) result.name = kit.name\n if (kit.description) result.description = kit.description\n if (logoUrls[0]) result.primaryLogoUrl = logoUrls[0]\n return result\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/brand-extraction/extract.ts","../../src/brand-extraction/map.ts"],"sourcesContent":["/**\n * Brand-kit extraction engine.\n *\n * Given a website URL (or raw HTML), parse the page and pull a typed BrandKit:\n * logo candidates, color palette, fonts, and prominent images. Parsing is\n * regex-based on purpose — this runs on Cloudflare Workers and other edge\n * runtimes where DOM libraries (jsdom/cheerio) are unavailable, and the page\n * structures we read (link tags, meta tags, CSS custom properties, font-family\n * declarations) are flat enough that a DOM buys nothing.\n *\n * Degrades gracefully: a missing favicon, no CSS tokens, or an image-only page\n * each narrow the kit rather than failing it. The ONLY hard failures are a bad\n * input (no html and no fetch) and a fetch error — both returned as a typed\n * `{ succeeded: false }` outcome so callers never mistake an empty kit for a\n * real one.\n */\n\nimport type {\n BrandColor,\n BrandExtractionResult,\n BrandFont,\n BrandImage,\n BrandKit,\n BrandLogoCandidate,\n ExtractBrandKitOptions,\n FetchLike,\n} from './types'\n\nconst DEFAULT_TIMEOUT_MS = 15000\nconst DEFAULT_MAX_PER_LIST = 12\n\n// ── URL helpers ──────────────────────────────────────────────────────────────\n\n/** Normalize a user-supplied site URL: add https:// when scheme-less, validate. */\nexport function normalizeSiteUrl(raw: string): string | null {\n const trimmed = raw.trim()\n if (!trimmed) return null\n // A non-http(s) scheme is an explicit reject — don't paper over it by\n // prepending https:// (that would turn \"ftp://x\" into host \"ftp\").\n if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed) && !/^https?:\\/\\//i.test(trimmed)) return null\n const withScheme = /^https?:\\/\\//i.test(trimmed) ? trimmed : `https://${trimmed}`\n try {\n const u = new URL(withScheme)\n if (u.protocol !== 'http:' && u.protocol !== 'https:') return null\n return u.toString()\n } catch {\n return null\n }\n}\n\n/** Resolve a possibly-relative href against the page URL. Returns null for\n * data: URIs and unresolvable values — we want servable http(s) URLs only. */\nfunction absolutize(href: string, base: string): string | null {\n const v = href.trim()\n if (!v || v.startsWith('data:') || v.startsWith('javascript:')) return null\n try {\n const u = new URL(v, base)\n if (u.protocol !== 'http:' && u.protocol !== 'https:') return null\n return u.toString()\n } catch {\n return null\n }\n}\n\n// ── Attribute parsing ────────────────────────────────────────────────────────\n\n/** Pull all `<tag ...>` open-tags from html (case-insensitive). */\nfunction matchTags(html: string, tag: string): string[] {\n const re = new RegExp(`<${tag}\\\\b[^>]*>`, 'gi')\n return html.match(re) ?? []\n}\n\n/** Read an attribute value from a single tag string. Handles quoted and\n * unquoted values. Returns undefined when absent. */\nfunction attr(tag: string, name: string): string | undefined {\n const quoted = new RegExp(`\\\\b${name}\\\\s*=\\\\s*[\"']([^\"']*)[\"']`, 'i').exec(tag)\n if (quoted) return decodeEntities(quoted[1] ?? '')\n const bare = new RegExp(`\\\\b${name}\\\\s*=\\\\s*([^\\\\s\"'>]+)`, 'i').exec(tag)\n return bare ? decodeEntities(bare[1] ?? '') : undefined\n}\n\nfunction decodeEntities(s: string): string {\n return s\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(///gi, '/')\n}\n\n// ── Name / description ───────────────────────────────────────────────────────\n\nfunction extractName(html: string): string | undefined {\n for (const tag of matchTags(html, 'meta')) {\n const prop = (attr(tag, 'property') ?? attr(tag, 'name'))?.toLowerCase()\n if (prop === 'og:site_name') {\n const c = attr(tag, 'content')?.trim()\n if (c) return c\n }\n }\n const title = /<title[^>]*>([\\s\\S]*?)<\\/title>/i.exec(html)?.[1]\n if (title) {\n // \"Acme — the best widget\" → \"Acme\". Split on common separators, take head.\n const head = (decodeEntities(title).split(/\\s+[|–—\\-:·]\\s+/)[0] ?? '').trim()\n if (head) return head\n }\n return undefined\n}\n\nfunction extractDescription(html: string): string | undefined {\n for (const tag of matchTags(html, 'meta')) {\n const prop = (attr(tag, 'property') ?? attr(tag, 'name'))?.toLowerCase()\n if (prop === 'description' || prop === 'og:description') {\n const c = attr(tag, 'content')?.trim()\n if (c) return c\n }\n }\n return undefined\n}\n\n// ── Logos ────────────────────────────────────────────────────────────────────\n\nconst MIME_BY_EXT: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n ico: 'image/x-icon',\n}\n\nfunction mimeFromUrl(url: string): string | undefined {\n const ext = new URL(url).pathname.split('.').pop()?.toLowerCase()\n return ext ? MIME_BY_EXT[ext] : undefined\n}\n\nfunction parseSizes(sizes: string | undefined): { width?: number; height?: number } {\n if (!sizes) return {}\n const m = /(\\d+)\\s*[x×]\\s*(\\d+)/i.exec(sizes)\n if (!m) return {}\n return { width: Number(m[1]), height: Number(m[2]) }\n}\n\nfunction extractLogos(html: string, base: string): BrandLogoCandidate[] {\n const out: BrandLogoCandidate[] = []\n const seen = new Set<string>()\n const push = (c: BrandLogoCandidate) => {\n if (seen.has(c.url)) return\n seen.add(c.url)\n out.push(c)\n }\n\n // link rel icons / apple-touch-icon\n for (const tag of matchTags(html, 'link')) {\n const rel = attr(tag, 'rel')?.toLowerCase() ?? ''\n const href = attr(tag, 'href')\n if (!href) continue\n const url = absolutize(href, base)\n if (!url) continue\n const { width, height } = parseSizes(attr(tag, 'sizes'))\n if (rel.includes('apple-touch-icon')) {\n push({ url, source: 'apple-touch-icon', confidence: 0.7, width, height, mimeType: mimeFromUrl(url) })\n } else if (rel.split(/\\s+/).includes('icon') || rel.includes('shortcut icon')) {\n push({ url, source: 'favicon', confidence: 0.5, width, height, mimeType: mimeFromUrl(url) })\n }\n }\n\n // og:image (often shows the logo in context — moderate confidence)\n for (const tag of matchTags(html, 'meta')) {\n const prop = (attr(tag, 'property') ?? attr(tag, 'name'))?.toLowerCase()\n if (prop === 'og:image' || prop === 'og:image:url') {\n const href = attr(tag, 'content')\n const url = href ? absolutize(href, base) : null\n if (url) push({ url, source: 'og:image', confidence: 0.55, mimeType: mimeFromUrl(url) })\n }\n }\n\n // <img> whose src/class/alt/id mentions \"logo\" — the strongest in-page signal\n for (const tag of matchTags(html, 'img')) {\n const src = attr(tag, 'src') ?? attr(tag, 'data-src')\n if (!src) continue\n const alt = attr(tag, 'alt')\n const cls = attr(tag, 'class') ?? ''\n const id = attr(tag, 'id') ?? ''\n const looksLikeLogo = /logo|brand|wordmark/i.test(`${src} ${alt ?? ''} ${cls} ${id}`)\n if (!looksLikeLogo) continue\n const url = absolutize(src, base)\n if (!url) continue\n const w = attr(tag, 'width')\n const h = attr(tag, 'height')\n push({\n url,\n source: 'img-logo',\n confidence: 0.85,\n alt,\n width: w ? Number(w) || undefined : undefined,\n height: h ? Number(h) || undefined : undefined,\n mimeType: mimeFromUrl(url),\n })\n }\n\n // No favicon link tag at all? Fall back to the conventional /favicon.ico —\n // it almost always exists. Lowest confidence.\n if (!out.some((l) => l.source === 'favicon' || l.source === 'apple-touch-icon')) {\n const fav = absolutize('/favicon.ico', base)\n if (fav) push({ url: fav, source: 'favicon', confidence: 0.3, mimeType: 'image/x-icon' })\n }\n\n return out.sort((a, b) => b.confidence - a.confidence)\n}\n\n// ── Colors ───────────────────────────────────────────────────────────────────\n\n/** Normalize any CSS color literal to #rrggbb / #rrggbbaa hex, or null. */\nexport function normalizeColor(raw: string): string | null {\n const v = raw.trim().toLowerCase()\n // #rgb / #rgba / #rrggbb / #rrggbbaa\n const hex = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.exec(v)\n if (hex) {\n const h = hex[1] ?? ''\n // Expand 3/4-digit shorthand by doubling each nibble.\n if (h.length === 3 || h.length === 4) {\n return `#${h.split('').map((c) => c + c).join('')}`\n }\n return `#${h}`\n }\n // rgb()/rgba()\n const rgb = /^rgba?\\(\\s*([\\d.]+)[\\s,]+([\\d.]+)[\\s,]+([\\d.]+)(?:[\\s,/]+([\\d.%]+))?\\s*\\)$/.exec(v)\n if (rgb) {\n const to255 = (n: string | undefined) => Math.max(0, Math.min(255, Math.round(Number(n))))\n const r = to255(rgb[1]).toString(16).padStart(2, '0')\n const g = to255(rgb[2]).toString(16).padStart(2, '0')\n const b = to255(rgb[3]).toString(16).padStart(2, '0')\n let a = ''\n if (rgb[4] !== undefined) {\n const av = rgb[4].endsWith('%') ? Number(rgb[4].slice(0, -1)) / 100 : Number(rgb[4])\n const ai = Math.max(0, Math.min(255, Math.round(av * 255)))\n if (ai < 255) a = ai.toString(16).padStart(2, '0')\n }\n return `#${r}${g}${b}${a}`\n }\n return null\n}\n\nconst COLOR_LITERAL_RE = /#[0-9a-fA-F]{3,8}\\b|rgba?\\([^)]*\\)/g\nconst ROOT_VAR_RE = /(--[a-z0-9-]*(?:color|colour|bg|background|accent|brand|primary|secondary|surface|text|fg|ink)[a-z0-9-]*)\\s*:\\s*([^;}{]+)/gi\n\nfunction extractPalette(html: string): BrandColor[] {\n const byHex = new Map<string, BrandColor>()\n const bump = (hex: string, fromToken: boolean, tokenName?: string) => {\n const existing = byHex.get(hex)\n if (existing) {\n existing.occurrences += 1\n if (fromToken && !existing.fromToken) {\n existing.fromToken = true\n existing.tokenName = tokenName\n }\n } else {\n byHex.set(hex, { hex, occurrences: 1, fromToken, ...(tokenName ? { tokenName } : {}) })\n }\n }\n\n // CSS custom properties — highest-fidelity design tokens.\n for (const m of html.matchAll(ROOT_VAR_RE)) {\n const tokenName = m[1]\n const value = m[2]\n if (!value) continue\n const lit = value.match(COLOR_LITERAL_RE)?.[0]\n if (!lit) continue\n const hex = normalizeColor(lit)\n if (hex) bump(hex, true, tokenName)\n }\n\n // All other color literals across the document (inline styles, <style>).\n for (const m of html.matchAll(COLOR_LITERAL_RE)) {\n const hex = normalizeColor(m[0])\n if (hex) bump(hex, false)\n }\n\n // Rank: token-sourced first, then by popularity. Drop pure white/black noise\n // to the back so a real brand color leads.\n const isNeutral = (h: string) => /^#(0{6}|f{6})(ff)?$/i.test(h)\n return [...byHex.values()].sort((a, b) => {\n if (a.fromToken !== b.fromToken) return a.fromToken ? -1 : 1\n const an = isNeutral(a.hex) ? 1 : 0\n const bn = isNeutral(b.hex) ? 1 : 0\n if (an !== bn) return an - bn\n return b.occurrences - a.occurrences\n })\n}\n\n// ── Fonts ────────────────────────────────────────────────────────────────────\n\nconst GENERIC_FAMILIES = new Set([\n 'serif', 'sans-serif', 'monospace', 'cursive', 'fantasy', 'system-ui',\n 'ui-sans-serif', 'ui-serif', 'ui-monospace', 'ui-rounded', 'inherit', 'initial', 'unset',\n])\n\n/** font-family declarations, with the selector chunk preceding them for role\n * inference. Captures the selector text in group 1, the stack in group 2. */\nconst FONT_DECL_RE = /([^{}]*)\\{[^{}]*font-family\\s*:\\s*([^;}{]+)[;}]/gi\n\nfunction parseFontStack(raw: string | undefined): string[] {\n if (!raw) return []\n return raw\n .split(',')\n .map((s) => s.trim().replace(/^[\"']|[\"']$/g, ''))\n .filter(Boolean)\n}\n\nfunction roleFromSelector(selector: string): 'display' | 'body' | 'unknown' {\n const s = selector.toLowerCase()\n if (/\\b(h[1-3]|\\.h[1-3]|heading|title|display|hero)\\b/.test(s)) return 'display'\n if (/\\b(body|p|html|\\.text|\\.content|root|:root|\\*)\\b/.test(s)) return 'body'\n return 'unknown'\n}\n\nfunction extractFonts(html: string): BrandFont[] {\n // Restrict to <style> blocks + the whole doc; inline style=\"\" attributes are\n // included because the regex matches any `{...font-family...}` chunk, but we\n // also scan style attributes explicitly below.\n const byFamily = new Map<string, BrandFont>()\n const consider = (family: string, stack: string[], role: BrandFont['role']) => {\n const key = family.toLowerCase()\n if (!family || GENERIC_FAMILIES.has(key)) return\n const existing = byFamily.get(key)\n if (existing) {\n existing.occurrences += 1\n if (existing.role === 'unknown' && role !== 'unknown') existing.role = role\n } else {\n byFamily.set(key, { family, stack, role, occurrences: 1 })\n }\n }\n\n for (const m of html.matchAll(FONT_DECL_RE)) {\n const selector = m[1] ?? ''\n const stack = parseFontStack(m[2])\n const primary = stack[0]\n if (!primary) continue\n consider(primary, stack, roleFromSelector(selector))\n }\n\n // Bare `font-family:` declarations inside inline style attributes and tokens.\n const BARE_RE = /font-family\\s*:\\s*([^;\"'}{]+)/gi\n for (const m of html.matchAll(BARE_RE)) {\n const stack = parseFontStack(m[1])\n const primary = stack[0]\n if (!primary) continue\n consider(primary, stack, 'unknown')\n }\n\n // Google Fonts <link href=\"...family=Inter:wght@400...\"> — strong signal.\n for (const tag of matchTags(html, 'link')) {\n const href = attr(tag, 'href') ?? ''\n if (!/fonts\\.googleapis\\.com/i.test(href)) continue\n for (const fam of href.matchAll(/family=([^:&]+)/gi)) {\n const captured = fam[1]\n if (!captured) continue\n const family = decodeURIComponent(captured.replace(/\\+/g, ' ')).trim()\n consider(family, [family], 'display')\n }\n }\n\n return [...byFamily.values()].sort((a, b) => {\n const rank = (r: BrandFont['role']) => (r === 'display' ? 0 : r === 'body' ? 1 : 2)\n const rr = rank(a.role) - rank(b.role)\n if (rr !== 0) return rr\n return b.occurrences - a.occurrences\n })\n}\n\n// ── Images ───────────────────────────────────────────────────────────────────\n\nfunction extractImages(html: string, base: string): BrandImage[] {\n const out: BrandImage[] = []\n const seen = new Set<string>()\n const push = (img: BrandImage) => {\n if (seen.has(img.url)) return\n seen.add(img.url)\n out.push(img)\n }\n\n for (const tag of matchTags(html, 'meta')) {\n const prop = (attr(tag, 'property') ?? attr(tag, 'name'))?.toLowerCase()\n const href = attr(tag, 'content')\n const url = href ? absolutize(href, base) : null\n if (!url) continue\n if (prop === 'og:image' || prop === 'og:image:url') push({ url, source: 'og:image' })\n else if (prop === 'twitter:image' || prop === 'twitter:image:src') push({ url, source: 'twitter:image' })\n }\n\n for (const tag of matchTags(html, 'img')) {\n const src = attr(tag, 'src') ?? attr(tag, 'data-src')\n if (!src) continue\n const url = absolutize(src, base)\n if (!url) continue\n const cls = `${attr(tag, 'class') ?? ''} ${attr(tag, 'id') ?? ''}`\n // Skip obvious logos/icons — those go in the logos list, not images.\n if (/logo|icon|favicon|wordmark/i.test(`${url} ${cls}`)) continue\n const isHero = /hero|banner|cover|feature|splash/i.test(cls)\n const w = attr(tag, 'width')\n const h = attr(tag, 'height')\n push({\n url,\n source: isHero ? 'img-hero' : 'img-content',\n alt: attr(tag, 'alt'),\n width: w ? Number(w) || undefined : undefined,\n height: h ? Number(h) || undefined : undefined,\n })\n }\n\n const rank = (s: BrandImage['source']) =>\n s === 'og:image' ? 0 : s === 'twitter:image' ? 1 : s === 'img-hero' ? 2 : 3\n return out.sort((a, b) => rank(a.source) - rank(b.source))\n}\n\n// ── Public API ───────────────────────────────────────────────────────────────\n\n/** Parse already-fetched HTML into a BrandKit. Pure — no network. Exposed so\n * callers that hold the HTML (or want to combine multiple pages) can reuse the\n * parsing without re-fetching. */\nexport function parseBrandKit(html: string, sourceUrl: string, maxPerList = DEFAULT_MAX_PER_LIST): BrandKit {\n const logos = extractLogos(html, sourceUrl).slice(0, maxPerList)\n const palette = extractPalette(html).slice(0, maxPerList)\n const fonts = extractFonts(html).slice(0, maxPerList)\n const images = extractImages(html, sourceUrl).slice(0, maxPerList)\n const name = extractName(html)\n const description = extractDescription(html)\n\n return {\n sourceUrl,\n ...(name ? { name } : {}),\n ...(description ? { description } : {}),\n logos,\n palette,\n fonts,\n images,\n extractedFrom: [sourceUrl],\n }\n}\n\n/**\n * Fetch a website (or use supplied HTML) and extract its BrandKit.\n *\n * Returns a typed outcome — callers MUST check `succeeded`. A fetch failure or\n * empty input is a real, surfaced error, never an empty kit masquerading as a\n * result. Parsing itself never throws: a malformed page yields a sparse kit\n * with warnings, which is information, not failure.\n */\nexport async function extractBrandKit(\n url: string,\n options: ExtractBrandKitOptions = {},\n): Promise<BrandExtractionResult> {\n const { html: providedHtml, fetchImpl, timeoutMs = DEFAULT_TIMEOUT_MS, maxPerList = DEFAULT_MAX_PER_LIST } = options\n const warnings: string[] = []\n\n const sourceUrl = normalizeSiteUrl(url)\n if (!sourceUrl) {\n return { succeeded: false, error: `Not a valid http(s) URL: ${JSON.stringify(url)}`, stage: 'input' }\n }\n\n let html = providedHtml\n if (html === undefined) {\n const doFetch: FetchLike | undefined =\n fetchImpl ?? (typeof globalThis.fetch === 'function'\n ? (u, init) => globalThis.fetch(u, init as RequestInit)\n : undefined)\n if (!doFetch) {\n return { succeeded: false, error: 'No html provided and no fetch implementation available', stage: 'input' }\n }\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), timeoutMs)\n try {\n const res = await doFetch(sourceUrl, {\n signal: controller.signal,\n headers: { 'user-agent': 'TangleBrandExtractor/1.0 (+https://tangle.tools)' },\n })\n if (!res.ok) {\n return { succeeded: false, error: `Fetch failed: HTTP ${res.status} for ${sourceUrl}`, stage: 'fetch' }\n }\n html = await res.text()\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err)\n return { succeeded: false, error: `Fetch error for ${sourceUrl}: ${reason}`, stage: 'fetch' }\n } finally {\n clearTimeout(timer)\n }\n }\n\n if (!html.trim()) {\n return { succeeded: false, error: `Empty document for ${sourceUrl}`, stage: 'parse' }\n }\n\n const kit = parseBrandKit(html, sourceUrl, maxPerList)\n\n if (kit.logos.length === 0) warnings.push('No logo candidates found.')\n if (kit.palette.length === 0) warnings.push('No colors extracted — page has no inline CSS or design tokens.')\n if (kit.fonts.length === 0) warnings.push('No custom fonts found — site likely uses system defaults.')\n if (kit.images.length === 0) warnings.push('No prominent images found.')\n\n return { succeeded: true, kit, warnings }\n}\n","/**\n * Pure mapping helpers from an extracted BrandKit onto consumable shapes.\n *\n * Extraction yields ranked candidate lists; products need decided roles\n * (background vs accent, display vs body). These helpers make the obvious,\n * defensible default choice and expose the reasoning so a confirmation UI can\n * show \"we picked X — change it?\". They NEVER invent a value: when a role can't\n * be filled from the kit, it is omitted, and the caller decides the fallback.\n */\n\nimport type { BrandColor, BrandFont, BrandKit } from './types'\n\n/** Relative luminance (0..1) of an #rrggbb(aa) hex — for light/dark sorting. */\nexport function luminance(hex: string): number {\n const h = hex.replace('#', '').slice(0, 6)\n const r = parseInt(h.slice(0, 2), 16) / 255\n const g = parseInt(h.slice(2, 4), 16) / 255\n const b = parseInt(h.slice(4, 6), 16) / 255\n const lin = (c: number) => (c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4)\n return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b)\n}\n\nfunction isGreyish(hex: string): boolean {\n const h = hex.replace('#', '').slice(0, 6)\n const r = parseInt(h.slice(0, 2), 16)\n const g = parseInt(h.slice(2, 4), 16)\n const b = parseInt(h.slice(4, 6), 16)\n const max = Math.max(r, g, b)\n const min = Math.min(r, g, b)\n return max - min < 18\n}\n\n/** Define a color palette with background, surface, text, and accent colors for UI elements */\nexport interface DecidedPalette {\n /** Lightest neutral — page background. */\n background?: string\n /** A raised neutral one step from background. */\n surface?: string\n /** Darkest readable color — primary text. */\n textPrimary?: string\n /** Mid-tone neutral — secondary text. */\n textSecondary?: string\n /** Most saturated / popular brand color — accent. */\n accent?: string\n /** Readable text color to sit on the accent (black or white by contrast). */\n accentText?: string\n}\n\n/**\n * Assign palette roles from the ranked colors. Heuristic, not authoritative —\n * a confirmation step should let the user correct it. Roles only appear when\n * the kit actually contained a color that fits.\n */\nexport function decidePalette(palette: BrandColor[]): DecidedPalette {\n if (palette.length === 0) return {}\n const hexes = palette.map((c) => c.hex)\n const greys = hexes.filter(isGreyish).sort((a, b) => luminance(b) - luminance(a))\n const colored = hexes.filter((h) => !isGreyish(h))\n\n // Accent: the top-ranked non-grey (token-first, popularity-first) color.\n const accent = colored[0]\n // Background: lightest grey (or lightest overall when no greys).\n const sortedLight = [...hexes].sort((a, b) => luminance(b) - luminance(a))\n const background = greys[0] ?? sortedLight[0]\n // Surface: next grey under background, else second-lightest.\n const surface = greys[1] ?? sortedLight.find((h) => h !== background)\n // Text primary: darkest color overall.\n const textPrimary = [...hexes].sort((a, b) => luminance(a) - luminance(b))[0]\n // Text secondary: a mid-luminance grey distinct from primary/background.\n const textSecondary = greys.find((h) => h !== background && h !== surface && h !== textPrimary)\n\n const result: DecidedPalette = {}\n if (background) result.background = background\n if (surface) result.surface = surface\n if (textPrimary) result.textPrimary = textPrimary\n if (textSecondary) result.textSecondary = textSecondary\n if (accent) {\n result.accent = accent\n result.accentText = luminance(accent) > 0.45 ? '#000000' : '#ffffff'\n }\n return result\n}\n\n/** Define font selections for display and body text with optional BrandFont properties */\nexport interface DecidedFonts {\n display?: BrandFont\n body?: BrandFont\n}\n\n/** Pick a display and body font from the ranked list. When only one usable\n * font exists it fills both roles — a single-typeface brand is valid. */\nexport function decideFonts(fonts: BrandFont[]): DecidedFonts {\n if (fonts.length === 0) return {}\n const display = fonts.find((f) => f.role === 'display') ?? fonts[0]\n const body = fonts.find((f) => f.role === 'body') ?? fonts.find((f) => f !== display) ?? display\n return { display, body }\n}\n\n/** Everything a confirmation step needs from a kit, with roles decided. */\nexport interface DecidedBrandKit {\n name?: string\n description?: string\n sourceUrl: string\n palette: DecidedPalette\n fonts: DecidedFonts\n /** Best logo URL, when any candidate was found. */\n primaryLogoUrl?: string\n /** All logo URLs, ranked. */\n logoUrls: string[]\n /** Prominent image URLs, ranked. */\n imageUrls: string[]\n extractedFrom: string[]\n}\n\n/** Collapse a raw BrandKit into decided roles — the shape a product persists. */\nexport function decideBrandKit(kit: BrandKit): DecidedBrandKit {\n const palette = decidePalette(kit.palette)\n const fonts = decideFonts(kit.fonts)\n const logoUrls = kit.logos.map((l) => l.url)\n const result: DecidedBrandKit = {\n sourceUrl: kit.sourceUrl,\n palette,\n fonts,\n logoUrls,\n imageUrls: kit.images.map((i) => i.url),\n extractedFrom: kit.extractedFrom,\n }\n if (kit.name) result.name = kit.name\n if (kit.description) result.description = kit.description\n if (logoUrls[0]) result.primaryLogoUrl = logoUrls[0]\n return result\n}\n"],"mappings":";AA4BA,IAAM,qBAAqB;AAC3B,IAAM,uBAAuB;AAKtB,SAAS,iBAAiB,KAA4B;AAC3D,QAAM,UAAU,IAAI,KAAK;AACzB,MAAI,CAAC,QAAS,QAAO;AAGrB,MAAI,uBAAuB,KAAK,OAAO,KAAK,CAAC,gBAAgB,KAAK,OAAO,EAAG,QAAO;AACnF,QAAM,aAAa,gBAAgB,KAAK,OAAO,IAAI,UAAU,WAAW,OAAO;AAC/E,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,UAAU;AAC5B,QAAI,EAAE,aAAa,WAAW,EAAE,aAAa,SAAU,QAAO;AAC9D,WAAO,EAAE,SAAS;AAAA,EACpB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAIA,SAAS,WAAW,MAAc,MAA6B;AAC7D,QAAM,IAAI,KAAK,KAAK;AACpB,MAAI,CAAC,KAAK,EAAE,WAAW,OAAO,KAAK,EAAE,WAAW,aAAa,EAAG,QAAO;AACvE,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,GAAG,IAAI;AACzB,QAAI,EAAE,aAAa,WAAW,EAAE,aAAa,SAAU,QAAO;AAC9D,WAAO,EAAE,SAAS;AAAA,EACpB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKA,SAAS,UAAU,MAAc,KAAuB;AACtD,QAAM,KAAK,IAAI,OAAO,IAAI,GAAG,aAAa,IAAI;AAC9C,SAAO,KAAK,MAAM,EAAE,KAAK,CAAC;AAC5B;AAIA,SAAS,KAAK,KAAa,MAAkC;AAC3D,QAAM,SAAS,IAAI,OAAO,MAAM,IAAI,6BAA6B,GAAG,EAAE,KAAK,GAAG;AAC9E,MAAI,OAAQ,QAAO,eAAe,OAAO,CAAC,KAAK,EAAE;AACjD,QAAM,OAAO,IAAI,OAAO,MAAM,IAAI,yBAAyB,GAAG,EAAE,KAAK,GAAG;AACxE,SAAO,OAAO,eAAe,KAAK,CAAC,KAAK,EAAE,IAAI;AAChD;AAEA,SAAS,eAAe,GAAmB;AACzC,SAAO,EACJ,QAAQ,UAAU,GAAG,EACrB,QAAQ,SAAS,GAAG,EACpB,QAAQ,SAAS,GAAG,EACpB,QAAQ,WAAW,GAAG,EACtB,QAAQ,UAAU,GAAG,EACrB,QAAQ,YAAY,GAAG;AAC5B;AAIA,SAAS,YAAY,MAAkC;AACrD,aAAW,OAAO,UAAU,MAAM,MAAM,GAAG;AACzC,UAAM,QAAQ,KAAK,KAAK,UAAU,KAAK,KAAK,KAAK,MAAM,IAAI,YAAY;AACvE,QAAI,SAAS,gBAAgB;AAC3B,YAAM,IAAI,KAAK,KAAK,SAAS,GAAG,KAAK;AACrC,UAAI,EAAG,QAAO;AAAA,IAChB;AAAA,EACF;AACA,QAAM,QAAQ,mCAAmC,KAAK,IAAI,IAAI,CAAC;AAC/D,MAAI,OAAO;AAET,UAAM,QAAQ,eAAe,KAAK,EAAE,MAAM,iBAAiB,EAAE,CAAC,KAAK,IAAI,KAAK;AAC5E,QAAI,KAAM,QAAO;AAAA,EACnB;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,MAAkC;AAC5D,aAAW,OAAO,UAAU,MAAM,MAAM,GAAG;AACzC,UAAM,QAAQ,KAAK,KAAK,UAAU,KAAK,KAAK,KAAK,MAAM,IAAI,YAAY;AACvE,QAAI,SAAS,iBAAiB,SAAS,kBAAkB;AACvD,YAAM,IAAI,KAAK,KAAK,SAAS,GAAG,KAAK;AACrC,UAAI,EAAG,QAAO;AAAA,IAChB;AAAA,EACF;AACA,SAAO;AACT;AAIA,IAAM,cAAsC;AAAA,EAC1C,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AACP;AAEA,SAAS,YAAY,KAAiC;AACpD,QAAM,MAAM,IAAI,IAAI,GAAG,EAAE,SAAS,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY;AAChE,SAAO,MAAM,YAAY,GAAG,IAAI;AAClC;AAEA,SAAS,WAAW,OAAgE;AAClF,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,QAAM,IAAI,wBAAwB,KAAK,KAAK;AAC5C,MAAI,CAAC,EAAG,QAAO,CAAC;AAChB,SAAO,EAAE,OAAO,OAAO,EAAE,CAAC,CAAC,GAAG,QAAQ,OAAO,EAAE,CAAC,CAAC,EAAE;AACrD;AAEA,SAAS,aAAa,MAAc,MAAoC;AACtE,QAAM,MAA4B,CAAC;AACnC,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,OAAO,CAAC,MAA0B;AACtC,QAAI,KAAK,IAAI,EAAE,GAAG,EAAG;AACrB,SAAK,IAAI,EAAE,GAAG;AACd,QAAI,KAAK,CAAC;AAAA,EACZ;AAGA,aAAW,OAAO,UAAU,MAAM,MAAM,GAAG;AACzC,UAAM,MAAM,KAAK,KAAK,KAAK,GAAG,YAAY,KAAK;AAC/C,UAAM,OAAO,KAAK,KAAK,MAAM;AAC7B,QAAI,CAAC,KAAM;AACX,UAAM,MAAM,WAAW,MAAM,IAAI;AACjC,QAAI,CAAC,IAAK;AACV,UAAM,EAAE,OAAO,OAAO,IAAI,WAAW,KAAK,KAAK,OAAO,CAAC;AACvD,QAAI,IAAI,SAAS,kBAAkB,GAAG;AACpC,WAAK,EAAE,KAAK,QAAQ,oBAAoB,YAAY,KAAK,OAAO,QAAQ,UAAU,YAAY,GAAG,EAAE,CAAC;AAAA,IACtG,WAAW,IAAI,MAAM,KAAK,EAAE,SAAS,MAAM,KAAK,IAAI,SAAS,eAAe,GAAG;AAC7E,WAAK,EAAE,KAAK,QAAQ,WAAW,YAAY,KAAK,OAAO,QAAQ,UAAU,YAAY,GAAG,EAAE,CAAC;AAAA,IAC7F;AAAA,EACF;AAGA,aAAW,OAAO,UAAU,MAAM,MAAM,GAAG;AACzC,UAAM,QAAQ,KAAK,KAAK,UAAU,KAAK,KAAK,KAAK,MAAM,IAAI,YAAY;AACvE,QAAI,SAAS,cAAc,SAAS,gBAAgB;AAClD,YAAM,OAAO,KAAK,KAAK,SAAS;AAChC,YAAM,MAAM,OAAO,WAAW,MAAM,IAAI,IAAI;AAC5C,UAAI,IAAK,MAAK,EAAE,KAAK,QAAQ,YAAY,YAAY,MAAM,UAAU,YAAY,GAAG,EAAE,CAAC;AAAA,IACzF;AAAA,EACF;AAGA,aAAW,OAAO,UAAU,MAAM,KAAK,GAAG;AACxC,UAAM,MAAM,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,UAAU;AACpD,QAAI,CAAC,IAAK;AACV,UAAM,MAAM,KAAK,KAAK,KAAK;AAC3B,UAAM,MAAM,KAAK,KAAK,OAAO,KAAK;AAClC,UAAM,KAAK,KAAK,KAAK,IAAI,KAAK;AAC9B,UAAM,gBAAgB,uBAAuB,KAAK,GAAG,GAAG,IAAI,OAAO,EAAE,IAAI,GAAG,IAAI,EAAE,EAAE;AACpF,QAAI,CAAC,cAAe;AACpB,UAAM,MAAM,WAAW,KAAK,IAAI;AAChC,QAAI,CAAC,IAAK;AACV,UAAM,IAAI,KAAK,KAAK,OAAO;AAC3B,UAAM,IAAI,KAAK,KAAK,QAAQ;AAC5B,SAAK;AAAA,MACH;AAAA,MACA,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ;AAAA,MACA,OAAO,IAAI,OAAO,CAAC,KAAK,SAAY;AAAA,MACpC,QAAQ,IAAI,OAAO,CAAC,KAAK,SAAY;AAAA,MACrC,UAAU,YAAY,GAAG;AAAA,IAC3B,CAAC;AAAA,EACH;AAIA,MAAI,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE,WAAW,aAAa,EAAE,WAAW,kBAAkB,GAAG;AAC/E,UAAM,MAAM,WAAW,gBAAgB,IAAI;AAC3C,QAAI,IAAK,MAAK,EAAE,KAAK,KAAK,QAAQ,WAAW,YAAY,KAAK,UAAU,eAAe,CAAC;AAAA,EAC1F;AAEA,SAAO,IAAI,KAAK,CAAC,GAAG,MAAM,EAAE,aAAa,EAAE,UAAU;AACvD;AAKO,SAAS,eAAe,KAA4B;AACzD,QAAM,IAAI,IAAI,KAAK,EAAE,YAAY;AAEjC,QAAM,MAAM,8CAA8C,KAAK,CAAC;AAChE,MAAI,KAAK;AACP,UAAM,IAAI,IAAI,CAAC,KAAK;AAEpB,QAAI,EAAE,WAAW,KAAK,EAAE,WAAW,GAAG;AACpC,aAAO,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC;AAAA,IACnD;AACA,WAAO,IAAI,CAAC;AAAA,EACd;AAEA,QAAM,MAAM,6EAA6E,KAAK,CAAC;AAC/F,MAAI,KAAK;AACP,UAAM,QAAQ,CAAC,MAA0B,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;AACzF,UAAM,IAAI,MAAM,IAAI,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AACpD,UAAM,IAAI,MAAM,IAAI,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AACpD,UAAM,IAAI,MAAM,IAAI,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AACpD,QAAI,IAAI;AACR,QAAI,IAAI,CAAC,MAAM,QAAW;AACxB,YAAM,KAAK,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI,OAAO,IAAI,CAAC,EAAE,MAAM,GAAG,EAAE,CAAC,IAAI,MAAM,OAAO,IAAI,CAAC,CAAC;AACnF,YAAM,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,KAAK,GAAG,CAAC,CAAC;AAC1D,UAAI,KAAK,IAAK,KAAI,GAAG,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAAA,IACnD;AACA,WAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;AAAA,EAC1B;AACA,SAAO;AACT;AAEA,IAAM,mBAAmB;AACzB,IAAM,cAAc;AAEpB,SAAS,eAAe,MAA4B;AAClD,QAAM,QAAQ,oBAAI,IAAwB;AAC1C,QAAM,OAAO,CAAC,KAAa,WAAoB,cAAuB;AACpE,UAAM,WAAW,MAAM,IAAI,GAAG;AAC9B,QAAI,UAAU;AACZ,eAAS,eAAe;AACxB,UAAI,aAAa,CAAC,SAAS,WAAW;AACpC,iBAAS,YAAY;AACrB,iBAAS,YAAY;AAAA,MACvB;AAAA,IACF,OAAO;AACL,YAAM,IAAI,KAAK,EAAE,KAAK,aAAa,GAAG,WAAW,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC,EAAG,CAAC;AAAA,IACxF;AAAA,EACF;AAGA,aAAW,KAAK,KAAK,SAAS,WAAW,GAAG;AAC1C,UAAM,YAAY,EAAE,CAAC;AACrB,UAAM,QAAQ,EAAE,CAAC;AACjB,QAAI,CAAC,MAAO;AACZ,UAAM,MAAM,MAAM,MAAM,gBAAgB,IAAI,CAAC;AAC7C,QAAI,CAAC,IAAK;AACV,UAAM,MAAM,eAAe,GAAG;AAC9B,QAAI,IAAK,MAAK,KAAK,MAAM,SAAS;AAAA,EACpC;AAGA,aAAW,KAAK,KAAK,SAAS,gBAAgB,GAAG;AAC/C,UAAM,MAAM,eAAe,EAAE,CAAC,CAAC;AAC/B,QAAI,IAAK,MAAK,KAAK,KAAK;AAAA,EAC1B;AAIA,QAAM,YAAY,CAAC,MAAc,uBAAuB,KAAK,CAAC;AAC9D,SAAO,CAAC,GAAG,MAAM,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM;AACxC,QAAI,EAAE,cAAc,EAAE,UAAW,QAAO,EAAE,YAAY,KAAK;AAC3D,UAAM,KAAK,UAAU,EAAE,GAAG,IAAI,IAAI;AAClC,UAAM,KAAK,UAAU,EAAE,GAAG,IAAI,IAAI;AAClC,QAAI,OAAO,GAAI,QAAO,KAAK;AAC3B,WAAO,EAAE,cAAc,EAAE;AAAA,EAC3B,CAAC;AACH;AAIA,IAAM,mBAAmB,oBAAI,IAAI;AAAA,EAC/B;AAAA,EAAS;AAAA,EAAc;AAAA,EAAa;AAAA,EAAW;AAAA,EAAW;AAAA,EAC1D;AAAA,EAAiB;AAAA,EAAY;AAAA,EAAgB;AAAA,EAAc;AAAA,EAAW;AAAA,EAAW;AACnF,CAAC;AAID,IAAM,eAAe;AAErB,SAAS,eAAe,KAAmC;AACzD,MAAI,CAAC,IAAK,QAAO,CAAC;AAClB,SAAO,IACJ,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,gBAAgB,EAAE,CAAC,EAC/C,OAAO,OAAO;AACnB;AAEA,SAAS,iBAAiB,UAAkD;AAC1E,QAAM,IAAI,SAAS,YAAY;AAC/B,MAAI,mDAAmD,KAAK,CAAC,EAAG,QAAO;AACvE,MAAI,mDAAmD,KAAK,CAAC,EAAG,QAAO;AACvE,SAAO;AACT;AAEA,SAAS,aAAa,MAA2B;AAI/C,QAAM,WAAW,oBAAI,IAAuB;AAC5C,QAAM,WAAW,CAAC,QAAgB,OAAiB,SAA4B;AAC7E,UAAM,MAAM,OAAO,YAAY;AAC/B,QAAI,CAAC,UAAU,iBAAiB,IAAI,GAAG,EAAG;AAC1C,UAAM,WAAW,SAAS,IAAI,GAAG;AACjC,QAAI,UAAU;AACZ,eAAS,eAAe;AACxB,UAAI,SAAS,SAAS,aAAa,SAAS,UAAW,UAAS,OAAO;AAAA,IACzE,OAAO;AACL,eAAS,IAAI,KAAK,EAAE,QAAQ,OAAO,MAAM,aAAa,EAAE,CAAC;AAAA,IAC3D;AAAA,EACF;AAEA,aAAW,KAAK,KAAK,SAAS,YAAY,GAAG;AAC3C,UAAM,WAAW,EAAE,CAAC,KAAK;AACzB,UAAM,QAAQ,eAAe,EAAE,CAAC,CAAC;AACjC,UAAM,UAAU,MAAM,CAAC;AACvB,QAAI,CAAC,QAAS;AACd,aAAS,SAAS,OAAO,iBAAiB,QAAQ,CAAC;AAAA,EACrD;AAGA,QAAM,UAAU;AAChB,aAAW,KAAK,KAAK,SAAS,OAAO,GAAG;AACtC,UAAM,QAAQ,eAAe,EAAE,CAAC,CAAC;AACjC,UAAM,UAAU,MAAM,CAAC;AACvB,QAAI,CAAC,QAAS;AACd,aAAS,SAAS,OAAO,SAAS;AAAA,EACpC;AAGA,aAAW,OAAO,UAAU,MAAM,MAAM,GAAG;AACzC,UAAM,OAAO,KAAK,KAAK,MAAM,KAAK;AAClC,QAAI,CAAC,0BAA0B,KAAK,IAAI,EAAG;AAC3C,eAAW,OAAO,KAAK,SAAS,mBAAmB,GAAG;AACpD,YAAM,WAAW,IAAI,CAAC;AACtB,UAAI,CAAC,SAAU;AACf,YAAM,SAAS,mBAAmB,SAAS,QAAQ,OAAO,GAAG,CAAC,EAAE,KAAK;AACrE,eAAS,QAAQ,CAAC,MAAM,GAAG,SAAS;AAAA,IACtC;AAAA,EACF;AAEA,SAAO,CAAC,GAAG,SAAS,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM;AAC3C,UAAM,OAAO,CAAC,MAA0B,MAAM,YAAY,IAAI,MAAM,SAAS,IAAI;AACjF,UAAM,KAAK,KAAK,EAAE,IAAI,IAAI,KAAK,EAAE,IAAI;AACrC,QAAI,OAAO,EAAG,QAAO;AACrB,WAAO,EAAE,cAAc,EAAE;AAAA,EAC3B,CAAC;AACH;AAIA,SAAS,cAAc,MAAc,MAA4B;AAC/D,QAAM,MAAoB,CAAC;AAC3B,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,OAAO,CAAC,QAAoB;AAChC,QAAI,KAAK,IAAI,IAAI,GAAG,EAAG;AACvB,SAAK,IAAI,IAAI,GAAG;AAChB,QAAI,KAAK,GAAG;AAAA,EACd;AAEA,aAAW,OAAO,UAAU,MAAM,MAAM,GAAG;AACzC,UAAM,QAAQ,KAAK,KAAK,UAAU,KAAK,KAAK,KAAK,MAAM,IAAI,YAAY;AACvE,UAAM,OAAO,KAAK,KAAK,SAAS;AAChC,UAAM,MAAM,OAAO,WAAW,MAAM,IAAI,IAAI;AAC5C,QAAI,CAAC,IAAK;AACV,QAAI,SAAS,cAAc,SAAS,eAAgB,MAAK,EAAE,KAAK,QAAQ,WAAW,CAAC;AAAA,aAC3E,SAAS,mBAAmB,SAAS,oBAAqB,MAAK,EAAE,KAAK,QAAQ,gBAAgB,CAAC;AAAA,EAC1G;AAEA,aAAW,OAAO,UAAU,MAAM,KAAK,GAAG;AACxC,UAAM,MAAM,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,UAAU;AACpD,QAAI,CAAC,IAAK;AACV,UAAM,MAAM,WAAW,KAAK,IAAI;AAChC,QAAI,CAAC,IAAK;AACV,UAAM,MAAM,GAAG,KAAK,KAAK,OAAO,KAAK,EAAE,IAAI,KAAK,KAAK,IAAI,KAAK,EAAE;AAEhE,QAAI,8BAA8B,KAAK,GAAG,GAAG,IAAI,GAAG,EAAE,EAAG;AACzD,UAAM,SAAS,oCAAoC,KAAK,GAAG;AAC3D,UAAM,IAAI,KAAK,KAAK,OAAO;AAC3B,UAAM,IAAI,KAAK,KAAK,QAAQ;AAC5B,SAAK;AAAA,MACH;AAAA,MACA,QAAQ,SAAS,aAAa;AAAA,MAC9B,KAAK,KAAK,KAAK,KAAK;AAAA,MACpB,OAAO,IAAI,OAAO,CAAC,KAAK,SAAY;AAAA,MACpC,QAAQ,IAAI,OAAO,CAAC,KAAK,SAAY;AAAA,IACvC,CAAC;AAAA,EACH;AAEA,QAAM,OAAO,CAAC,MACZ,MAAM,aAAa,IAAI,MAAM,kBAAkB,IAAI,MAAM,aAAa,IAAI;AAC5E,SAAO,IAAI,KAAK,CAAC,GAAG,MAAM,KAAK,EAAE,MAAM,IAAI,KAAK,EAAE,MAAM,CAAC;AAC3D;AAOO,SAAS,cAAc,MAAc,WAAmB,aAAa,sBAAgC;AAC1G,QAAM,QAAQ,aAAa,MAAM,SAAS,EAAE,MAAM,GAAG,UAAU;AAC/D,QAAM,UAAU,eAAe,IAAI,EAAE,MAAM,GAAG,UAAU;AACxD,QAAM,QAAQ,aAAa,IAAI,EAAE,MAAM,GAAG,UAAU;AACpD,QAAM,SAAS,cAAc,MAAM,SAAS,EAAE,MAAM,GAAG,UAAU;AACjE,QAAM,OAAO,YAAY,IAAI;AAC7B,QAAM,cAAc,mBAAmB,IAAI;AAE3C,SAAO;AAAA,IACL;AAAA,IACA,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,IACvB,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;AAAA,IACrC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe,CAAC,SAAS;AAAA,EAC3B;AACF;AAUA,eAAsB,gBACpB,KACA,UAAkC,CAAC,GACH;AAChC,QAAM,EAAE,MAAM,cAAc,WAAW,YAAY,oBAAoB,aAAa,qBAAqB,IAAI;AAC7G,QAAM,WAAqB,CAAC;AAE5B,QAAM,YAAY,iBAAiB,GAAG;AACtC,MAAI,CAAC,WAAW;AACd,WAAO,EAAE,WAAW,OAAO,OAAO,4BAA4B,KAAK,UAAU,GAAG,CAAC,IAAI,OAAO,QAAQ;AAAA,EACtG;AAEA,MAAI,OAAO;AACX,MAAI,SAAS,QAAW;AACtB,UAAM,UACJ,cAAc,OAAO,WAAW,UAAU,aACtC,CAAC,GAAG,SAAS,WAAW,MAAM,GAAG,IAAmB,IACpD;AACN,QAAI,CAAC,SAAS;AACZ,aAAO,EAAE,WAAW,OAAO,OAAO,0DAA0D,OAAO,QAAQ;AAAA,IAC7G;AACA,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,SAAS;AAC5D,QAAI;AACF,YAAM,MAAM,MAAM,QAAQ,WAAW;AAAA,QACnC,QAAQ,WAAW;AAAA,QACnB,SAAS,EAAE,cAAc,mDAAmD;AAAA,MAC9E,CAAC;AACD,UAAI,CAAC,IAAI,IAAI;AACX,eAAO,EAAE,WAAW,OAAO,OAAO,sBAAsB,IAAI,MAAM,QAAQ,SAAS,IAAI,OAAO,QAAQ;AAAA,MACxG;AACA,aAAO,MAAM,IAAI,KAAK;AAAA,IACxB,SAAS,KAAK;AACZ,YAAM,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC9D,aAAO,EAAE,WAAW,OAAO,OAAO,mBAAmB,SAAS,KAAK,MAAM,IAAI,OAAO,QAAQ;AAAA,IAC9F,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF;AAEA,MAAI,CAAC,KAAK,KAAK,GAAG;AAChB,WAAO,EAAE,WAAW,OAAO,OAAO,sBAAsB,SAAS,IAAI,OAAO,QAAQ;AAAA,EACtF;AAEA,QAAM,MAAM,cAAc,MAAM,WAAW,UAAU;AAErD,MAAI,IAAI,MAAM,WAAW,EAAG,UAAS,KAAK,2BAA2B;AACrE,MAAI,IAAI,QAAQ,WAAW,EAAG,UAAS,KAAK,qEAAgE;AAC5G,MAAI,IAAI,MAAM,WAAW,EAAG,UAAS,KAAK,gEAA2D;AACrG,MAAI,IAAI,OAAO,WAAW,EAAG,UAAS,KAAK,4BAA4B;AAEvE,SAAO,EAAE,WAAW,MAAM,KAAK,SAAS;AAC1C;;;AC1eO,SAAS,UAAU,KAAqB;AAC7C,QAAM,IAAI,IAAI,QAAQ,KAAK,EAAE,EAAE,MAAM,GAAG,CAAC;AACzC,QAAM,IAAI,SAAS,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI;AACxC,QAAM,IAAI,SAAS,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI;AACxC,QAAM,IAAI,SAAS,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI;AACxC,QAAM,MAAM,CAAC,MAAe,KAAK,UAAU,IAAI,UAAU,IAAI,SAAS,UAAU;AAChF,SAAO,SAAS,IAAI,CAAC,IAAI,SAAS,IAAI,CAAC,IAAI,SAAS,IAAI,CAAC;AAC3D;AAEA,SAAS,UAAU,KAAsB;AACvC,QAAM,IAAI,IAAI,QAAQ,KAAK,EAAE,EAAE,MAAM,GAAG,CAAC;AACzC,QAAM,IAAI,SAAS,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE;AACpC,QAAM,IAAI,SAAS,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE;AACpC,QAAM,IAAI,SAAS,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE;AACpC,QAAM,MAAM,KAAK,IAAI,GAAG,GAAG,CAAC;AAC5B,QAAM,MAAM,KAAK,IAAI,GAAG,GAAG,CAAC;AAC5B,SAAO,MAAM,MAAM;AACrB;AAuBO,SAAS,cAAc,SAAuC;AACnE,MAAI,QAAQ,WAAW,EAAG,QAAO,CAAC;AAClC,QAAM,QAAQ,QAAQ,IAAI,CAAC,MAAM,EAAE,GAAG;AACtC,QAAM,QAAQ,MAAM,OAAO,SAAS,EAAE,KAAK,CAAC,GAAG,MAAM,UAAU,CAAC,IAAI,UAAU,CAAC,CAAC;AAChF,QAAM,UAAU,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;AAGjD,QAAM,SAAS,QAAQ,CAAC;AAExB,QAAM,cAAc,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,UAAU,CAAC,IAAI,UAAU,CAAC,CAAC;AACzE,QAAM,aAAa,MAAM,CAAC,KAAK,YAAY,CAAC;AAE5C,QAAM,UAAU,MAAM,CAAC,KAAK,YAAY,KAAK,CAAC,MAAM,MAAM,UAAU;AAEpE,QAAM,cAAc,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,UAAU,CAAC,IAAI,UAAU,CAAC,CAAC,EAAE,CAAC;AAE5E,QAAM,gBAAgB,MAAM,KAAK,CAAC,MAAM,MAAM,cAAc,MAAM,WAAW,MAAM,WAAW;AAE9F,QAAM,SAAyB,CAAC;AAChC,MAAI,WAAY,QAAO,aAAa;AACpC,MAAI,QAAS,QAAO,UAAU;AAC9B,MAAI,YAAa,QAAO,cAAc;AACtC,MAAI,cAAe,QAAO,gBAAgB;AAC1C,MAAI,QAAQ;AACV,WAAO,SAAS;AAChB,WAAO,aAAa,UAAU,MAAM,IAAI,OAAO,YAAY;AAAA,EAC7D;AACA,SAAO;AACT;AAUO,SAAS,YAAY,OAAkC;AAC5D,MAAI,MAAM,WAAW,EAAG,QAAO,CAAC;AAChC,QAAM,UAAU,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,SAAS,KAAK,MAAM,CAAC;AAClE,QAAM,OAAO,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM,KAAK,MAAM,KAAK,CAAC,MAAM,MAAM,OAAO,KAAK;AACzF,SAAO,EAAE,SAAS,KAAK;AACzB;AAmBO,SAAS,eAAe,KAAgC;AAC7D,QAAM,UAAU,cAAc,IAAI,OAAO;AACzC,QAAM,QAAQ,YAAY,IAAI,KAAK;AACnC,QAAM,WAAW,IAAI,MAAM,IAAI,CAAC,MAAM,EAAE,GAAG;AAC3C,QAAM,SAA0B;AAAA,IAC9B,WAAW,IAAI;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,IAAI,OAAO,IAAI,CAAC,MAAM,EAAE,GAAG;AAAA,IACtC,eAAe,IAAI;AAAA,EACrB;AACA,MAAI,IAAI,KAAM,QAAO,OAAO,IAAI;AAChC,MAAI,IAAI,YAAa,QAAO,cAAc,IAAI;AAC9C,MAAI,SAAS,CAAC,EAAG,QAAO,iBAAiB,SAAS,CAAC;AACnD,SAAO;AACT;","names":[]}
|
package/dist/catalog/index.d.ts
CHANGED
|
@@ -41,6 +41,7 @@ interface RouterModel {
|
|
|
41
41
|
provider?: string;
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
|
+
/** Define the structure and capabilities of a catalog item with optional pricing and feature flags */
|
|
44
45
|
interface CatalogModel {
|
|
45
46
|
id: string;
|
|
46
47
|
name: string;
|
|
@@ -55,6 +56,7 @@ interface CatalogModel {
|
|
|
55
56
|
supportsReasoning: boolean;
|
|
56
57
|
featured: boolean;
|
|
57
58
|
}
|
|
59
|
+
/** Define a catalog containing models with a default ID and fetch timestamp */
|
|
58
60
|
interface ModelCatalog {
|
|
59
61
|
defaultModelId: string | null;
|
|
60
62
|
fetchedAt: string;
|