@frontmcp/ui 0.6.0 → 0.6.2
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/README.md +140 -362
- package/bridge/core/bridge-factory.d.ts +1 -0
- package/bridge/core/bridge-factory.d.ts.map +1 -1
- package/bridge/index.d.ts +1 -1
- package/bridge/index.d.ts.map +1 -1
- package/bridge/index.js +39 -881
- package/bridge/runtime/index.d.ts +2 -1
- package/bridge/runtime/index.d.ts.map +1 -1
- package/bundler/browser-components.d.ts +42 -0
- package/bundler/browser-components.d.ts.map +1 -0
- package/bundler/bundler.d.ts +78 -4
- package/bundler/bundler.d.ts.map +1 -1
- package/bundler/index.d.ts +8 -8
- package/bundler/index.d.ts.map +1 -1
- package/bundler/index.js +1411 -2997
- package/bundler/types.d.ts +188 -7
- package/bundler/types.d.ts.map +1 -1
- package/components/alert.schema.d.ts +6 -6
- package/components/avatar.schema.d.ts +9 -9
- package/components/badge.schema.d.ts +9 -9
- package/components/button.schema.d.ts +9 -9
- package/components/card.schema.d.ts +7 -7
- package/components/form.schema.d.ts +24 -24
- package/components/index.js +128 -198
- package/components/modal.schema.d.ts +8 -8
- package/components/table.schema.d.ts +6 -6
- package/esm/bridge/{index.js → index.mjs} +40 -877
- package/esm/bundler/index.mjs +3136 -0
- package/esm/components/{index.js → index.mjs} +136 -196
- package/esm/index.mjs +5450 -0
- package/esm/layouts/index.mjs +409 -0
- package/esm/package.json +15 -32
- package/esm/react/{index.js → index.mjs} +71 -260
- package/esm/renderers/index.mjs +611 -0
- package/esm/universal/index.mjs +1951 -0
- package/esm/web-components/{index.js → index.mjs} +232 -287
- package/index.d.ts +22 -41
- package/index.d.ts.map +1 -1
- package/index.js +4286 -19607
- package/layouts/base.d.ts +2 -2
- package/layouts/base.d.ts.map +1 -1
- package/layouts/index.js +46 -539
- package/layouts/presets.d.ts.map +1 -1
- package/package.json +15 -32
- package/react/Alert.d.ts +1 -2
- package/react/Alert.d.ts.map +1 -1
- package/react/Badge.d.ts +1 -2
- package/react/Badge.d.ts.map +1 -1
- package/react/Button.d.ts +1 -2
- package/react/Button.d.ts.map +1 -1
- package/react/Card.d.ts +1 -2
- package/react/Card.d.ts.map +1 -1
- package/react/hooks/context.d.ts +1 -1
- package/react/hooks/context.d.ts.map +1 -1
- package/react/index.d.ts +5 -7
- package/react/index.d.ts.map +1 -1
- package/react/index.js +55 -269
- package/react/types.d.ts +1 -2
- package/react/types.d.ts.map +1 -1
- package/renderers/index.d.ts +15 -25
- package/renderers/index.d.ts.map +1 -1
- package/renderers/index.js +393 -1619
- package/renderers/mdx.renderer.d.ts +13 -34
- package/renderers/mdx.renderer.d.ts.map +1 -1
- package/{esm/runtime/adapters → renderers}/react.adapter.d.ts +2 -2
- package/renderers/react.adapter.d.ts.map +1 -0
- package/renderers/react.renderer.d.ts +25 -16
- package/renderers/react.renderer.d.ts.map +1 -1
- package/renderers/transpiler.d.ts +49 -0
- package/renderers/transpiler.d.ts.map +1 -0
- package/universal/cached-runtime.d.ts +25 -1
- package/universal/cached-runtime.d.ts.map +1 -1
- package/universal/index.js +2037 -0
- package/universal/runtime-builder.d.ts.map +1 -1
- package/universal/types.d.ts.map +1 -1
- package/web-components/elements/fmcp-input.d.ts.map +1 -1
- package/web-components/elements/fmcp-select.d.ts.map +1 -1
- package/web-components/index.d.ts +0 -1
- package/web-components/index.d.ts.map +1 -1
- package/web-components/index.js +224 -289
- package/adapters/index.d.ts +0 -13
- package/adapters/index.d.ts.map +0 -1
- package/adapters/index.js +0 -462
- package/adapters/platform-meta.d.ts +0 -166
- package/adapters/platform-meta.d.ts.map +0 -1
- package/adapters/response-builder.d.ts +0 -108
- package/adapters/response-builder.d.ts.map +0 -1
- package/adapters/serving-mode.d.ts +0 -107
- package/adapters/serving-mode.d.ts.map +0 -1
- package/base-template/bridge.d.ts +0 -90
- package/base-template/bridge.d.ts.map +0 -1
- package/base-template/default-base-template.d.ts +0 -92
- package/base-template/default-base-template.d.ts.map +0 -1
- package/base-template/index.d.ts +0 -15
- package/base-template/index.d.ts.map +0 -1
- package/base-template/index.js +0 -1398
- package/base-template/polyfills.d.ts +0 -31
- package/base-template/polyfills.d.ts.map +0 -1
- package/base-template/theme-styles.d.ts +0 -74
- package/base-template/theme-styles.d.ts.map +0 -1
- package/build/cdn-resources.d.ts +0 -243
- package/build/cdn-resources.d.ts.map +0 -1
- package/build/index.d.ts +0 -295
- package/build/index.d.ts.map +0 -1
- package/build/index.js +0 -7096
- package/build/widget-manifest.d.ts +0 -362
- package/build/widget-manifest.d.ts.map +0 -1
- package/bundler/cache.d.ts +0 -173
- package/bundler/cache.d.ts.map +0 -1
- package/bundler/file-cache/component-builder.d.ts +0 -167
- package/bundler/file-cache/component-builder.d.ts.map +0 -1
- package/bundler/file-cache/hash-calculator.d.ts +0 -155
- package/bundler/file-cache/hash-calculator.d.ts.map +0 -1
- package/bundler/file-cache/index.d.ts +0 -12
- package/bundler/file-cache/index.d.ts.map +0 -1
- package/bundler/file-cache/storage/filesystem.d.ts +0 -149
- package/bundler/file-cache/storage/filesystem.d.ts.map +0 -1
- package/bundler/file-cache/storage/index.d.ts +0 -11
- package/bundler/file-cache/storage/index.d.ts.map +0 -1
- package/bundler/file-cache/storage/interface.d.ts +0 -152
- package/bundler/file-cache/storage/interface.d.ts.map +0 -1
- package/bundler/file-cache/storage/redis.d.ts +0 -139
- package/bundler/file-cache/storage/redis.d.ts.map +0 -1
- package/bundler/sandbox/enclave-adapter.d.ts +0 -121
- package/bundler/sandbox/enclave-adapter.d.ts.map +0 -1
- package/bundler/sandbox/executor.d.ts +0 -14
- package/bundler/sandbox/executor.d.ts.map +0 -1
- package/bundler/sandbox/policy.d.ts +0 -62
- package/bundler/sandbox/policy.d.ts.map +0 -1
- package/dependency/cdn-registry.d.ts +0 -98
- package/dependency/cdn-registry.d.ts.map +0 -1
- package/dependency/import-map.d.ts +0 -186
- package/dependency/import-map.d.ts.map +0 -1
- package/dependency/import-parser.d.ts +0 -82
- package/dependency/import-parser.d.ts.map +0 -1
- package/dependency/index.d.ts +0 -17
- package/dependency/index.d.ts.map +0 -1
- package/dependency/resolver.d.ts +0 -164
- package/dependency/resolver.d.ts.map +0 -1
- package/dependency/schemas.d.ts +0 -486
- package/dependency/schemas.d.ts.map +0 -1
- package/dependency/template-loader.d.ts +0 -204
- package/dependency/template-loader.d.ts.map +0 -1
- package/dependency/template-processor.d.ts +0 -118
- package/dependency/template-processor.d.ts.map +0 -1
- package/dependency/types.d.ts +0 -739
- package/dependency/types.d.ts.map +0 -1
- package/esm/adapters/index.d.ts +0 -13
- package/esm/adapters/index.d.ts.map +0 -1
- package/esm/adapters/index.js +0 -427
- package/esm/adapters/platform-meta.d.ts +0 -166
- package/esm/adapters/platform-meta.d.ts.map +0 -1
- package/esm/adapters/response-builder.d.ts +0 -108
- package/esm/adapters/response-builder.d.ts.map +0 -1
- package/esm/adapters/serving-mode.d.ts +0 -107
- package/esm/adapters/serving-mode.d.ts.map +0 -1
- package/esm/base-template/bridge.d.ts +0 -90
- package/esm/base-template/bridge.d.ts.map +0 -1
- package/esm/base-template/default-base-template.d.ts +0 -92
- package/esm/base-template/default-base-template.d.ts.map +0 -1
- package/esm/base-template/index.d.ts +0 -15
- package/esm/base-template/index.d.ts.map +0 -1
- package/esm/base-template/index.js +0 -1364
- package/esm/base-template/polyfills.d.ts +0 -31
- package/esm/base-template/polyfills.d.ts.map +0 -1
- package/esm/base-template/theme-styles.d.ts +0 -74
- package/esm/base-template/theme-styles.d.ts.map +0 -1
- package/esm/bridge/adapters/base-adapter.d.ts +0 -104
- package/esm/bridge/adapters/base-adapter.d.ts.map +0 -1
- package/esm/bridge/adapters/claude.adapter.d.ts +0 -67
- package/esm/bridge/adapters/claude.adapter.d.ts.map +0 -1
- package/esm/bridge/adapters/ext-apps.adapter.d.ts +0 -143
- package/esm/bridge/adapters/ext-apps.adapter.d.ts.map +0 -1
- package/esm/bridge/adapters/gemini.adapter.d.ts +0 -64
- package/esm/bridge/adapters/gemini.adapter.d.ts.map +0 -1
- package/esm/bridge/adapters/generic.adapter.d.ts +0 -56
- package/esm/bridge/adapters/generic.adapter.d.ts.map +0 -1
- package/esm/bridge/adapters/index.d.ts +0 -26
- package/esm/bridge/adapters/index.d.ts.map +0 -1
- package/esm/bridge/adapters/openai.adapter.d.ts +0 -65
- package/esm/bridge/adapters/openai.adapter.d.ts.map +0 -1
- package/esm/bridge/core/adapter-registry.d.ts +0 -122
- package/esm/bridge/core/adapter-registry.d.ts.map +0 -1
- package/esm/bridge/core/bridge-factory.d.ts +0 -199
- package/esm/bridge/core/bridge-factory.d.ts.map +0 -1
- package/esm/bridge/core/index.d.ts +0 -10
- package/esm/bridge/core/index.d.ts.map +0 -1
- package/esm/bridge/index.d.ts +0 -62
- package/esm/bridge/index.d.ts.map +0 -1
- package/esm/bridge/runtime/iife-generator.d.ts +0 -62
- package/esm/bridge/runtime/iife-generator.d.ts.map +0 -1
- package/esm/bridge/runtime/index.d.ts +0 -9
- package/esm/bridge/runtime/index.d.ts.map +0 -1
- package/esm/bridge/types.d.ts +0 -386
- package/esm/bridge/types.d.ts.map +0 -1
- package/esm/build/cdn-resources.d.ts +0 -243
- package/esm/build/cdn-resources.d.ts.map +0 -1
- package/esm/build/index.d.ts +0 -295
- package/esm/build/index.d.ts.map +0 -1
- package/esm/build/index.js +0 -7021
- package/esm/build/widget-manifest.d.ts +0 -362
- package/esm/build/widget-manifest.d.ts.map +0 -1
- package/esm/bundler/bundler.d.ts +0 -208
- package/esm/bundler/bundler.d.ts.map +0 -1
- package/esm/bundler/cache.d.ts +0 -173
- package/esm/bundler/cache.d.ts.map +0 -1
- package/esm/bundler/file-cache/component-builder.d.ts +0 -167
- package/esm/bundler/file-cache/component-builder.d.ts.map +0 -1
- package/esm/bundler/file-cache/hash-calculator.d.ts +0 -155
- package/esm/bundler/file-cache/hash-calculator.d.ts.map +0 -1
- package/esm/bundler/file-cache/index.d.ts +0 -12
- package/esm/bundler/file-cache/index.d.ts.map +0 -1
- package/esm/bundler/file-cache/storage/filesystem.d.ts +0 -149
- package/esm/bundler/file-cache/storage/filesystem.d.ts.map +0 -1
- package/esm/bundler/file-cache/storage/index.d.ts +0 -11
- package/esm/bundler/file-cache/storage/index.d.ts.map +0 -1
- package/esm/bundler/file-cache/storage/interface.d.ts +0 -152
- package/esm/bundler/file-cache/storage/interface.d.ts.map +0 -1
- package/esm/bundler/file-cache/storage/redis.d.ts +0 -139
- package/esm/bundler/file-cache/storage/redis.d.ts.map +0 -1
- package/esm/bundler/index.d.ts +0 -43
- package/esm/bundler/index.d.ts.map +0 -1
- package/esm/bundler/index.js +0 -4687
- package/esm/bundler/sandbox/enclave-adapter.d.ts +0 -121
- package/esm/bundler/sandbox/enclave-adapter.d.ts.map +0 -1
- package/esm/bundler/sandbox/executor.d.ts +0 -14
- package/esm/bundler/sandbox/executor.d.ts.map +0 -1
- package/esm/bundler/sandbox/policy.d.ts +0 -62
- package/esm/bundler/sandbox/policy.d.ts.map +0 -1
- package/esm/bundler/types.d.ts +0 -702
- package/esm/bundler/types.d.ts.map +0 -1
- package/esm/components/alert.d.ts +0 -66
- package/esm/components/alert.d.ts.map +0 -1
- package/esm/components/alert.schema.d.ts +0 -98
- package/esm/components/alert.schema.d.ts.map +0 -1
- package/esm/components/avatar.d.ts +0 -77
- package/esm/components/avatar.d.ts.map +0 -1
- package/esm/components/avatar.schema.d.ts +0 -170
- package/esm/components/avatar.schema.d.ts.map +0 -1
- package/esm/components/badge.d.ts +0 -64
- package/esm/components/badge.d.ts.map +0 -1
- package/esm/components/badge.schema.d.ts +0 -91
- package/esm/components/badge.schema.d.ts.map +0 -1
- package/esm/components/button.d.ts +0 -100
- package/esm/components/button.d.ts.map +0 -1
- package/esm/components/button.schema.d.ts +0 -120
- package/esm/components/button.schema.d.ts.map +0 -1
- package/esm/components/card.d.ts +0 -53
- package/esm/components/card.d.ts.map +0 -1
- package/esm/components/card.schema.d.ts +0 -93
- package/esm/components/card.schema.d.ts.map +0 -1
- package/esm/components/form.d.ts +0 -212
- package/esm/components/form.d.ts.map +0 -1
- package/esm/components/form.schema.d.ts +0 -365
- package/esm/components/form.schema.d.ts.map +0 -1
- package/esm/components/index.d.ts +0 -29
- package/esm/components/index.d.ts.map +0 -1
- package/esm/components/list.d.ts +0 -121
- package/esm/components/list.d.ts.map +0 -1
- package/esm/components/list.schema.d.ts +0 -129
- package/esm/components/list.schema.d.ts.map +0 -1
- package/esm/components/modal.d.ts +0 -100
- package/esm/components/modal.d.ts.map +0 -1
- package/esm/components/modal.schema.d.ts +0 -151
- package/esm/components/modal.schema.d.ts.map +0 -1
- package/esm/components/table.d.ts +0 -91
- package/esm/components/table.d.ts.map +0 -1
- package/esm/components/table.schema.d.ts +0 -123
- package/esm/components/table.schema.d.ts.map +0 -1
- package/esm/dependency/cdn-registry.d.ts +0 -98
- package/esm/dependency/cdn-registry.d.ts.map +0 -1
- package/esm/dependency/import-map.d.ts +0 -186
- package/esm/dependency/import-map.d.ts.map +0 -1
- package/esm/dependency/import-parser.d.ts +0 -82
- package/esm/dependency/import-parser.d.ts.map +0 -1
- package/esm/dependency/index.d.ts +0 -17
- package/esm/dependency/index.d.ts.map +0 -1
- package/esm/dependency/resolver.d.ts +0 -164
- package/esm/dependency/resolver.d.ts.map +0 -1
- package/esm/dependency/schemas.d.ts +0 -486
- package/esm/dependency/schemas.d.ts.map +0 -1
- package/esm/dependency/template-loader.d.ts +0 -204
- package/esm/dependency/template-loader.d.ts.map +0 -1
- package/esm/dependency/template-processor.d.ts +0 -118
- package/esm/dependency/template-processor.d.ts.map +0 -1
- package/esm/dependency/types.d.ts +0 -739
- package/esm/dependency/types.d.ts.map +0 -1
- package/esm/handlebars/expression-extractor.d.ts +0 -147
- package/esm/handlebars/expression-extractor.d.ts.map +0 -1
- package/esm/handlebars/helpers.d.ts +0 -339
- package/esm/handlebars/helpers.d.ts.map +0 -1
- package/esm/handlebars/index.d.ts +0 -195
- package/esm/handlebars/index.d.ts.map +0 -1
- package/esm/handlebars/index.js +0 -587
- package/esm/index.d.ts +0 -56
- package/esm/index.d.ts.map +0 -1
- package/esm/index.js +0 -20511
- package/esm/layouts/base.d.ts +0 -86
- package/esm/layouts/base.d.ts.map +0 -1
- package/esm/layouts/index.d.ts +0 -8
- package/esm/layouts/index.d.ts.map +0 -1
- package/esm/layouts/index.js +0 -892
- package/esm/layouts/presets.d.ts +0 -134
- package/esm/layouts/presets.d.ts.map +0 -1
- package/esm/pages/consent.d.ts +0 -117
- package/esm/pages/consent.d.ts.map +0 -1
- package/esm/pages/error.d.ts +0 -101
- package/esm/pages/error.d.ts.map +0 -1
- package/esm/pages/index.d.ts +0 -9
- package/esm/pages/index.d.ts.map +0 -1
- package/esm/pages/index.js +0 -1563
- package/esm/react/Alert.d.ts +0 -102
- package/esm/react/Alert.d.ts.map +0 -1
- package/esm/react/Badge.d.ts +0 -101
- package/esm/react/Badge.d.ts.map +0 -1
- package/esm/react/Button.d.ts +0 -109
- package/esm/react/Button.d.ts.map +0 -1
- package/esm/react/Card.d.ts +0 -104
- package/esm/react/Card.d.ts.map +0 -1
- package/esm/react/hooks/context.d.ts +0 -179
- package/esm/react/hooks/context.d.ts.map +0 -1
- package/esm/react/hooks/index.d.ts +0 -42
- package/esm/react/hooks/index.d.ts.map +0 -1
- package/esm/react/hooks/tools.d.ts +0 -284
- package/esm/react/hooks/tools.d.ts.map +0 -1
- package/esm/react/index.d.ts +0 -81
- package/esm/react/index.d.ts.map +0 -1
- package/esm/react/types.d.ts +0 -106
- package/esm/react/types.d.ts.map +0 -1
- package/esm/react/utils.d.ts +0 -43
- package/esm/react/utils.d.ts.map +0 -1
- package/esm/registry/index.d.ts +0 -46
- package/esm/registry/index.d.ts.map +0 -1
- package/esm/registry/index.js +0 -6422
- package/esm/registry/render-template.d.ts +0 -91
- package/esm/registry/render-template.d.ts.map +0 -1
- package/esm/registry/tool-ui.registry.d.ts +0 -294
- package/esm/registry/tool-ui.registry.d.ts.map +0 -1
- package/esm/registry/uri-utils.d.ts +0 -56
- package/esm/registry/uri-utils.d.ts.map +0 -1
- package/esm/render/index.d.ts +0 -8
- package/esm/render/index.d.ts.map +0 -1
- package/esm/render/prerender.d.ts +0 -57
- package/esm/render/prerender.d.ts.map +0 -1
- package/esm/renderers/cache.d.ts +0 -145
- package/esm/renderers/cache.d.ts.map +0 -1
- package/esm/renderers/html.renderer.d.ts +0 -123
- package/esm/renderers/html.renderer.d.ts.map +0 -1
- package/esm/renderers/index.d.ts +0 -36
- package/esm/renderers/index.d.ts.map +0 -1
- package/esm/renderers/index.js +0 -1827
- package/esm/renderers/mdx.renderer.d.ts +0 -120
- package/esm/renderers/mdx.renderer.d.ts.map +0 -1
- package/esm/renderers/react.renderer.d.ts +0 -96
- package/esm/renderers/react.renderer.d.ts.map +0 -1
- package/esm/renderers/registry.d.ts +0 -134
- package/esm/renderers/registry.d.ts.map +0 -1
- package/esm/renderers/types.d.ts +0 -342
- package/esm/renderers/types.d.ts.map +0 -1
- package/esm/renderers/utils/detect.d.ts +0 -107
- package/esm/renderers/utils/detect.d.ts.map +0 -1
- package/esm/renderers/utils/hash.d.ts +0 -40
- package/esm/renderers/utils/hash.d.ts.map +0 -1
- package/esm/renderers/utils/index.d.ts +0 -9
- package/esm/renderers/utils/index.d.ts.map +0 -1
- package/esm/renderers/utils/transpiler.d.ts +0 -89
- package/esm/renderers/utils/transpiler.d.ts.map +0 -1
- package/esm/runtime/adapters/html.adapter.d.ts +0 -59
- package/esm/runtime/adapters/html.adapter.d.ts.map +0 -1
- package/esm/runtime/adapters/index.d.ts +0 -26
- package/esm/runtime/adapters/index.d.ts.map +0 -1
- package/esm/runtime/adapters/mdx.adapter.d.ts +0 -73
- package/esm/runtime/adapters/mdx.adapter.d.ts.map +0 -1
- package/esm/runtime/adapters/react.adapter.d.ts.map +0 -1
- package/esm/runtime/adapters/types.d.ts +0 -95
- package/esm/runtime/adapters/types.d.ts.map +0 -1
- package/esm/runtime/csp.d.ts +0 -48
- package/esm/runtime/csp.d.ts.map +0 -1
- package/esm/runtime/index.d.ts +0 -17
- package/esm/runtime/index.d.ts.map +0 -1
- package/esm/runtime/index.js +0 -5186
- package/esm/runtime/mcp-bridge.d.ts +0 -101
- package/esm/runtime/mcp-bridge.d.ts.map +0 -1
- package/esm/runtime/renderer-runtime.d.ts +0 -133
- package/esm/runtime/renderer-runtime.d.ts.map +0 -1
- package/esm/runtime/sanitizer.d.ts +0 -172
- package/esm/runtime/sanitizer.d.ts.map +0 -1
- package/esm/runtime/types.d.ts +0 -415
- package/esm/runtime/types.d.ts.map +0 -1
- package/esm/runtime/wrapper.d.ts +0 -421
- package/esm/runtime/wrapper.d.ts.map +0 -1
- package/esm/styles/index.d.ts +0 -8
- package/esm/styles/index.d.ts.map +0 -1
- package/esm/styles/index.js +0 -171
- package/esm/styles/variants.d.ts +0 -51
- package/esm/styles/variants.d.ts.map +0 -1
- package/esm/theme/cdn.d.ts +0 -195
- package/esm/theme/cdn.d.ts.map +0 -1
- package/esm/theme/index.d.ts +0 -18
- package/esm/theme/index.d.ts.map +0 -1
- package/esm/theme/index.js +0 -700
- package/esm/theme/platforms.d.ts +0 -107
- package/esm/theme/platforms.d.ts.map +0 -1
- package/esm/theme/presets/github-openai.d.ts +0 -50
- package/esm/theme/presets/github-openai.d.ts.map +0 -1
- package/esm/theme/presets/index.d.ts +0 -11
- package/esm/theme/presets/index.d.ts.map +0 -1
- package/esm/theme/theme.d.ts +0 -396
- package/esm/theme/theme.d.ts.map +0 -1
- package/esm/tool-template/builder.d.ts +0 -213
- package/esm/tool-template/builder.d.ts.map +0 -1
- package/esm/tool-template/index.d.ts +0 -16
- package/esm/tool-template/index.d.ts.map +0 -1
- package/esm/tool-template/index.js +0 -3515
- package/esm/types/index.d.ts +0 -14
- package/esm/types/index.d.ts.map +0 -1
- package/esm/types/index.js +0 -75
- package/esm/types/ui-config.d.ts +0 -639
- package/esm/types/ui-config.d.ts.map +0 -1
- package/esm/types/ui-runtime.d.ts +0 -1007
- package/esm/types/ui-runtime.d.ts.map +0 -1
- package/esm/typings/cache/cache-adapter.d.ts +0 -125
- package/esm/typings/cache/cache-adapter.d.ts.map +0 -1
- package/esm/typings/cache/index.d.ts +0 -10
- package/esm/typings/cache/index.d.ts.map +0 -1
- package/esm/typings/cache/memory-cache.d.ts +0 -92
- package/esm/typings/cache/memory-cache.d.ts.map +0 -1
- package/esm/typings/dts-parser.d.ts +0 -90
- package/esm/typings/dts-parser.d.ts.map +0 -1
- package/esm/typings/index.d.ts +0 -48
- package/esm/typings/index.d.ts.map +0 -1
- package/esm/typings/schemas.d.ts +0 -232
- package/esm/typings/schemas.d.ts.map +0 -1
- package/esm/typings/type-fetcher.d.ts +0 -89
- package/esm/typings/type-fetcher.d.ts.map +0 -1
- package/esm/typings/types.d.ts +0 -320
- package/esm/typings/types.d.ts.map +0 -1
- package/esm/universal/UniversalApp.d.ts +0 -108
- package/esm/universal/UniversalApp.d.ts.map +0 -1
- package/esm/universal/cached-runtime.d.ts +0 -115
- package/esm/universal/cached-runtime.d.ts.map +0 -1
- package/esm/universal/context.d.ts +0 -122
- package/esm/universal/context.d.ts.map +0 -1
- package/esm/universal/index.d.ts +0 -57
- package/esm/universal/index.d.ts.map +0 -1
- package/esm/universal/renderers/html.renderer.d.ts +0 -37
- package/esm/universal/renderers/html.renderer.d.ts.map +0 -1
- package/esm/universal/renderers/index.d.ts +0 -112
- package/esm/universal/renderers/index.d.ts.map +0 -1
- package/esm/universal/renderers/markdown.renderer.d.ts +0 -33
- package/esm/universal/renderers/markdown.renderer.d.ts.map +0 -1
- package/esm/universal/renderers/mdx.renderer.d.ts +0 -38
- package/esm/universal/renderers/mdx.renderer.d.ts.map +0 -1
- package/esm/universal/renderers/react.renderer.d.ts +0 -46
- package/esm/universal/renderers/react.renderer.d.ts.map +0 -1
- package/esm/universal/runtime-builder.d.ts +0 -33
- package/esm/universal/runtime-builder.d.ts.map +0 -1
- package/esm/universal/store.d.ts +0 -135
- package/esm/universal/store.d.ts.map +0 -1
- package/esm/universal/types.d.ts +0 -199
- package/esm/universal/types.d.ts.map +0 -1
- package/esm/utils/escape-html.d.ts +0 -58
- package/esm/utils/escape-html.d.ts.map +0 -1
- package/esm/utils/index.d.ts +0 -10
- package/esm/utils/index.d.ts.map +0 -1
- package/esm/utils/index.js +0 -40
- package/esm/utils/safe-stringify.d.ts +0 -30
- package/esm/utils/safe-stringify.d.ts.map +0 -1
- package/esm/validation/error-box.d.ts +0 -56
- package/esm/validation/error-box.d.ts.map +0 -1
- package/esm/validation/index.d.ts +0 -13
- package/esm/validation/index.d.ts.map +0 -1
- package/esm/validation/index.js +0 -562
- package/esm/validation/schema-paths.d.ts +0 -118
- package/esm/validation/schema-paths.d.ts.map +0 -1
- package/esm/validation/template-validator.d.ts +0 -143
- package/esm/validation/template-validator.d.ts.map +0 -1
- package/esm/validation/wrapper.d.ts +0 -97
- package/esm/validation/wrapper.d.ts.map +0 -1
- package/esm/web-components/core/attribute-parser.d.ts +0 -82
- package/esm/web-components/core/attribute-parser.d.ts.map +0 -1
- package/esm/web-components/core/base-element.d.ts +0 -197
- package/esm/web-components/core/base-element.d.ts.map +0 -1
- package/esm/web-components/core/index.d.ts +0 -9
- package/esm/web-components/core/index.d.ts.map +0 -1
- package/esm/web-components/elements/fmcp-alert.d.ts +0 -46
- package/esm/web-components/elements/fmcp-alert.d.ts.map +0 -1
- package/esm/web-components/elements/fmcp-badge.d.ts +0 -47
- package/esm/web-components/elements/fmcp-badge.d.ts.map +0 -1
- package/esm/web-components/elements/fmcp-button.d.ts +0 -117
- package/esm/web-components/elements/fmcp-button.d.ts.map +0 -1
- package/esm/web-components/elements/fmcp-card.d.ts +0 -53
- package/esm/web-components/elements/fmcp-card.d.ts.map +0 -1
- package/esm/web-components/elements/fmcp-input.d.ts +0 -96
- package/esm/web-components/elements/fmcp-input.d.ts.map +0 -1
- package/esm/web-components/elements/fmcp-select.d.ts +0 -100
- package/esm/web-components/elements/fmcp-select.d.ts.map +0 -1
- package/esm/web-components/elements/index.d.ts +0 -13
- package/esm/web-components/elements/index.d.ts.map +0 -1
- package/esm/web-components/index.d.ts +0 -50
- package/esm/web-components/index.d.ts.map +0 -1
- package/esm/web-components/register.d.ts +0 -57
- package/esm/web-components/register.d.ts.map +0 -1
- package/esm/web-components/types.d.ts +0 -122
- package/esm/web-components/types.d.ts.map +0 -1
- package/esm/widgets/index.d.ts +0 -8
- package/esm/widgets/index.d.ts.map +0 -1
- package/esm/widgets/index.js +0 -941
- package/esm/widgets/progress.d.ts +0 -133
- package/esm/widgets/progress.d.ts.map +0 -1
- package/esm/widgets/resource.d.ts +0 -163
- package/esm/widgets/resource.d.ts.map +0 -1
- package/handlebars/expression-extractor.d.ts +0 -147
- package/handlebars/expression-extractor.d.ts.map +0 -1
- package/handlebars/helpers.d.ts +0 -339
- package/handlebars/helpers.d.ts.map +0 -1
- package/handlebars/index.d.ts +0 -195
- package/handlebars/index.d.ts.map +0 -1
- package/handlebars/index.js +0 -666
- package/pages/consent.d.ts +0 -117
- package/pages/consent.d.ts.map +0 -1
- package/pages/error.d.ts +0 -101
- package/pages/error.d.ts.map +0 -1
- package/pages/index.d.ts +0 -9
- package/pages/index.d.ts.map +0 -1
- package/pages/index.js +0 -1602
- package/react/utils.d.ts +0 -43
- package/react/utils.d.ts.map +0 -1
- package/registry/index.d.ts +0 -46
- package/registry/index.d.ts.map +0 -1
- package/registry/index.js +0 -6465
- package/registry/render-template.d.ts +0 -91
- package/registry/render-template.d.ts.map +0 -1
- package/registry/tool-ui.registry.d.ts +0 -294
- package/registry/tool-ui.registry.d.ts.map +0 -1
- package/registry/uri-utils.d.ts +0 -56
- package/registry/uri-utils.d.ts.map +0 -1
- package/renderers/cache.d.ts +0 -145
- package/renderers/cache.d.ts.map +0 -1
- package/renderers/html.renderer.d.ts +0 -123
- package/renderers/html.renderer.d.ts.map +0 -1
- package/renderers/registry.d.ts +0 -134
- package/renderers/registry.d.ts.map +0 -1
- package/renderers/types.d.ts +0 -342
- package/renderers/types.d.ts.map +0 -1
- package/renderers/utils/detect.d.ts +0 -107
- package/renderers/utils/detect.d.ts.map +0 -1
- package/renderers/utils/hash.d.ts +0 -40
- package/renderers/utils/hash.d.ts.map +0 -1
- package/renderers/utils/index.d.ts +0 -9
- package/renderers/utils/index.d.ts.map +0 -1
- package/renderers/utils/transpiler.d.ts +0 -89
- package/renderers/utils/transpiler.d.ts.map +0 -1
- package/runtime/adapters/html.adapter.d.ts +0 -59
- package/runtime/adapters/html.adapter.d.ts.map +0 -1
- package/runtime/adapters/index.d.ts +0 -26
- package/runtime/adapters/index.d.ts.map +0 -1
- package/runtime/adapters/mdx.adapter.d.ts +0 -73
- package/runtime/adapters/mdx.adapter.d.ts.map +0 -1
- package/runtime/adapters/react.adapter.d.ts +0 -70
- package/runtime/adapters/react.adapter.d.ts.map +0 -1
- package/runtime/adapters/types.d.ts +0 -95
- package/runtime/adapters/types.d.ts.map +0 -1
- package/runtime/csp.d.ts +0 -48
- package/runtime/csp.d.ts.map +0 -1
- package/runtime/index.d.ts +0 -17
- package/runtime/index.d.ts.map +0 -1
- package/runtime/index.js +0 -5264
- package/runtime/mcp-bridge.d.ts +0 -101
- package/runtime/mcp-bridge.d.ts.map +0 -1
- package/runtime/renderer-runtime.d.ts +0 -133
- package/runtime/renderer-runtime.d.ts.map +0 -1
- package/runtime/sanitizer.d.ts +0 -172
- package/runtime/sanitizer.d.ts.map +0 -1
- package/runtime/types.d.ts +0 -415
- package/runtime/types.d.ts.map +0 -1
- package/runtime/wrapper.d.ts +0 -421
- package/runtime/wrapper.d.ts.map +0 -1
- package/styles/index.d.ts +0 -8
- package/styles/index.d.ts.map +0 -1
- package/styles/index.js +0 -222
- package/styles/variants.d.ts +0 -51
- package/styles/variants.d.ts.map +0 -1
- package/theme/cdn.d.ts +0 -195
- package/theme/cdn.d.ts.map +0 -1
- package/theme/index.d.ts +0 -18
- package/theme/index.d.ts.map +0 -1
- package/theme/index.js +0 -757
- package/theme/platforms.d.ts +0 -107
- package/theme/platforms.d.ts.map +0 -1
- package/theme/presets/github-openai.d.ts +0 -50
- package/theme/presets/github-openai.d.ts.map +0 -1
- package/theme/presets/index.d.ts +0 -11
- package/theme/presets/index.d.ts.map +0 -1
- package/theme/theme.d.ts +0 -396
- package/theme/theme.d.ts.map +0 -1
- package/tool-template/builder.d.ts +0 -213
- package/tool-template/builder.d.ts.map +0 -1
- package/tool-template/index.d.ts +0 -16
- package/tool-template/index.d.ts.map +0 -1
- package/tool-template/index.js +0 -3559
- package/types/index.d.ts +0 -14
- package/types/index.d.ts.map +0 -1
- package/types/index.js +0 -108
- package/types/ui-config.d.ts +0 -639
- package/types/ui-config.d.ts.map +0 -1
- package/types/ui-runtime.d.ts +0 -1007
- package/types/ui-runtime.d.ts.map +0 -1
- package/typings/cache/cache-adapter.d.ts +0 -125
- package/typings/cache/cache-adapter.d.ts.map +0 -1
- package/typings/cache/index.d.ts +0 -10
- package/typings/cache/index.d.ts.map +0 -1
- package/typings/cache/memory-cache.d.ts +0 -92
- package/typings/cache/memory-cache.d.ts.map +0 -1
- package/typings/dts-parser.d.ts +0 -90
- package/typings/dts-parser.d.ts.map +0 -1
- package/typings/index.d.ts +0 -48
- package/typings/index.d.ts.map +0 -1
- package/typings/schemas.d.ts +0 -232
- package/typings/schemas.d.ts.map +0 -1
- package/typings/type-fetcher.d.ts +0 -89
- package/typings/type-fetcher.d.ts.map +0 -1
- package/typings/types.d.ts +0 -320
- package/typings/types.d.ts.map +0 -1
- package/utils/escape-html.d.ts +0 -58
- package/utils/escape-html.d.ts.map +0 -1
- package/utils/index.d.ts +0 -10
- package/utils/index.d.ts.map +0 -1
- package/utils/index.js +0 -70
- package/utils/safe-stringify.d.ts +0 -30
- package/utils/safe-stringify.d.ts.map +0 -1
- package/validation/error-box.d.ts +0 -56
- package/validation/error-box.d.ts.map +0 -1
- package/validation/index.d.ts +0 -13
- package/validation/index.d.ts.map +0 -1
- package/validation/index.js +0 -603
- package/validation/schema-paths.d.ts +0 -118
- package/validation/schema-paths.d.ts.map +0 -1
- package/validation/template-validator.d.ts +0 -143
- package/validation/template-validator.d.ts.map +0 -1
- package/validation/wrapper.d.ts +0 -97
- package/validation/wrapper.d.ts.map +0 -1
- package/widgets/index.d.ts +0 -8
- package/widgets/index.d.ts.map +0 -1
- package/widgets/index.js +0 -978
- package/widgets/progress.d.ts +0 -133
- package/widgets/progress.d.ts.map +0 -1
- package/widgets/resource.d.ts +0 -163
- package/widgets/resource.d.ts.map +0 -1
- /package/esm/render/{index.js → index.mjs} +0 -0
package/bundler/index.js
CHANGED
|
@@ -5,9 +5,6 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __esm = (fn, res) => function __init() {
|
|
9
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
-
};
|
|
11
8
|
var __export = (target, all) => {
|
|
12
9
|
for (var name in all)
|
|
13
10
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -30,678 +27,56 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
27
|
));
|
|
31
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
29
|
|
|
33
|
-
// libs/ui/src/bundler/file-cache/storage/interface.ts
|
|
34
|
-
function calculateManifestSize(manifest) {
|
|
35
|
-
try {
|
|
36
|
-
return Buffer.byteLength(JSON.stringify(manifest), "utf8");
|
|
37
|
-
} catch {
|
|
38
|
-
return 0;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
var DEFAULT_STORAGE_OPTIONS;
|
|
42
|
-
var init_interface = __esm({
|
|
43
|
-
"libs/ui/src/bundler/file-cache/storage/interface.ts"() {
|
|
44
|
-
"use strict";
|
|
45
|
-
DEFAULT_STORAGE_OPTIONS = {
|
|
46
|
-
maxEntries: 1e3,
|
|
47
|
-
maxSize: 100 * 1024 * 1024,
|
|
48
|
-
// 100MB
|
|
49
|
-
defaultTtl: 24 * 60 * 60,
|
|
50
|
-
// 24 hours
|
|
51
|
-
compress: false
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
// libs/ui/src/bundler/file-cache/storage/filesystem.ts
|
|
57
|
-
var filesystem_exports = {};
|
|
58
|
-
__export(filesystem_exports, {
|
|
59
|
-
CacheInitializationError: () => CacheInitializationError,
|
|
60
|
-
CacheOperationError: () => CacheOperationError,
|
|
61
|
-
FilesystemStorage: () => FilesystemStorage,
|
|
62
|
-
StorageNotInitializedError: () => StorageNotInitializedError,
|
|
63
|
-
createFilesystemStorage: () => createFilesystemStorage
|
|
64
|
-
});
|
|
65
|
-
function createFilesystemStorage(options) {
|
|
66
|
-
return new FilesystemStorage(options);
|
|
67
|
-
}
|
|
68
|
-
var import_promises, import_path, import_fs, import_crypto, CacheInitializationError, CacheOperationError, StorageNotInitializedError, DEFAULT_FS_OPTIONS, FilesystemStorage;
|
|
69
|
-
var init_filesystem = __esm({
|
|
70
|
-
"libs/ui/src/bundler/file-cache/storage/filesystem.ts"() {
|
|
71
|
-
"use strict";
|
|
72
|
-
import_promises = require("fs/promises");
|
|
73
|
-
import_path = require("path");
|
|
74
|
-
import_fs = require("fs");
|
|
75
|
-
import_crypto = require("crypto");
|
|
76
|
-
init_interface();
|
|
77
|
-
CacheInitializationError = class extends Error {
|
|
78
|
-
cause;
|
|
79
|
-
constructor(message, cause) {
|
|
80
|
-
super(message);
|
|
81
|
-
this.name = "CacheInitializationError";
|
|
82
|
-
this.cause = cause;
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
CacheOperationError = class extends Error {
|
|
86
|
-
cause;
|
|
87
|
-
constructor(message, cause) {
|
|
88
|
-
super(message);
|
|
89
|
-
this.name = "CacheOperationError";
|
|
90
|
-
this.cause = cause;
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
StorageNotInitializedError = class extends Error {
|
|
94
|
-
constructor() {
|
|
95
|
-
super("Storage not initialized. Call initialize() first.");
|
|
96
|
-
this.name = "StorageNotInitializedError";
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
DEFAULT_FS_OPTIONS = {
|
|
100
|
-
...DEFAULT_STORAGE_OPTIONS,
|
|
101
|
-
cacheDir: ".frontmcp-cache/builds",
|
|
102
|
-
extension: ".json"
|
|
103
|
-
};
|
|
104
|
-
FilesystemStorage = class {
|
|
105
|
-
type = "filesystem";
|
|
106
|
-
options;
|
|
107
|
-
initialized = false;
|
|
108
|
-
stats = {
|
|
109
|
-
entries: 0,
|
|
110
|
-
totalSize: 0,
|
|
111
|
-
hits: 0,
|
|
112
|
-
misses: 0,
|
|
113
|
-
hitRate: 0
|
|
114
|
-
};
|
|
115
|
-
constructor(options = {}) {
|
|
116
|
-
this.options = {
|
|
117
|
-
...DEFAULT_FS_OPTIONS,
|
|
118
|
-
...options
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Initialize the storage directory.
|
|
123
|
-
*/
|
|
124
|
-
async initialize() {
|
|
125
|
-
if (this.initialized) return;
|
|
126
|
-
try {
|
|
127
|
-
await (0, import_promises.mkdir)(this.options.cacheDir, { recursive: true });
|
|
128
|
-
await this.loadStats();
|
|
129
|
-
this.initialized = true;
|
|
130
|
-
} catch (error) {
|
|
131
|
-
throw new CacheInitializationError(`Failed to initialize cache directory: ${error}`, error);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Get a cached manifest.
|
|
136
|
-
*/
|
|
137
|
-
async get(key) {
|
|
138
|
-
this.ensureInitialized();
|
|
139
|
-
const filePath = this.getFilePath(key);
|
|
140
|
-
try {
|
|
141
|
-
if (!(0, import_fs.existsSync)(filePath)) {
|
|
142
|
-
this.stats.misses++;
|
|
143
|
-
this.updateHitRate();
|
|
144
|
-
return void 0;
|
|
145
|
-
}
|
|
146
|
-
const content = await (0, import_promises.readFile)(filePath, "utf8");
|
|
147
|
-
const entry = JSON.parse(content);
|
|
148
|
-
if (Date.now() > entry.metadata.expiresAt) {
|
|
149
|
-
await this.delete(key);
|
|
150
|
-
this.stats.misses++;
|
|
151
|
-
this.updateHitRate();
|
|
152
|
-
return void 0;
|
|
153
|
-
}
|
|
154
|
-
entry.metadata.lastAccessedAt = Date.now();
|
|
155
|
-
entry.metadata.accessCount++;
|
|
156
|
-
this.writeEntry(filePath, entry).catch((err) => {
|
|
157
|
-
if (process.env["DEBUG"]) {
|
|
158
|
-
console.debug(`[FilesystemStorage] Failed to update cache metadata for ${key}: ${err}`);
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
this.stats.hits++;
|
|
162
|
-
this.updateHitRate();
|
|
163
|
-
return entry.data;
|
|
164
|
-
} catch {
|
|
165
|
-
this.stats.misses++;
|
|
166
|
-
this.updateHitRate();
|
|
167
|
-
return void 0;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* Store a manifest in cache.
|
|
172
|
-
*/
|
|
173
|
-
async set(key, manifest, ttl) {
|
|
174
|
-
this.ensureInitialized();
|
|
175
|
-
const filePath = this.getFilePath(key);
|
|
176
|
-
const size = calculateManifestSize(manifest);
|
|
177
|
-
const effectiveTtl = ttl ?? this.options.defaultTtl;
|
|
178
|
-
await this.ensureCapacity(size);
|
|
179
|
-
const entry = {
|
|
180
|
-
data: manifest,
|
|
181
|
-
metadata: {
|
|
182
|
-
key,
|
|
183
|
-
size,
|
|
184
|
-
createdAt: Date.now(),
|
|
185
|
-
expiresAt: Date.now() + effectiveTtl * 1e3,
|
|
186
|
-
lastAccessedAt: Date.now(),
|
|
187
|
-
accessCount: 0
|
|
188
|
-
}
|
|
189
|
-
};
|
|
190
|
-
await this.writeEntry(filePath, entry);
|
|
191
|
-
this.stats.entries++;
|
|
192
|
-
this.stats.totalSize += size;
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Check if a key exists.
|
|
196
|
-
*/
|
|
197
|
-
async has(key) {
|
|
198
|
-
this.ensureInitialized();
|
|
199
|
-
const filePath = this.getFilePath(key);
|
|
200
|
-
try {
|
|
201
|
-
if (!(0, import_fs.existsSync)(filePath)) return false;
|
|
202
|
-
const content = await (0, import_promises.readFile)(filePath, "utf8");
|
|
203
|
-
const entry = JSON.parse(content);
|
|
204
|
-
if (Date.now() > entry.metadata.expiresAt) {
|
|
205
|
-
await this.delete(key);
|
|
206
|
-
return false;
|
|
207
|
-
}
|
|
208
|
-
return true;
|
|
209
|
-
} catch {
|
|
210
|
-
return false;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Delete a cached entry.
|
|
215
|
-
*/
|
|
216
|
-
async delete(key) {
|
|
217
|
-
this.ensureInitialized();
|
|
218
|
-
const filePath = this.getFilePath(key);
|
|
219
|
-
try {
|
|
220
|
-
if (!(0, import_fs.existsSync)(filePath)) return false;
|
|
221
|
-
const content = await (0, import_promises.readFile)(filePath, "utf8");
|
|
222
|
-
const entry = JSON.parse(content);
|
|
223
|
-
await (0, import_promises.unlink)(filePath);
|
|
224
|
-
this.stats.entries = Math.max(0, this.stats.entries - 1);
|
|
225
|
-
this.stats.totalSize = Math.max(0, this.stats.totalSize - entry.metadata.size);
|
|
226
|
-
return true;
|
|
227
|
-
} catch {
|
|
228
|
-
return false;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* Clear all cached entries.
|
|
233
|
-
*/
|
|
234
|
-
async clear() {
|
|
235
|
-
this.ensureInitialized();
|
|
236
|
-
try {
|
|
237
|
-
await (0, import_promises.rm)(this.options.cacheDir, { recursive: true, force: true });
|
|
238
|
-
await (0, import_promises.mkdir)(this.options.cacheDir, { recursive: true });
|
|
239
|
-
this.stats = {
|
|
240
|
-
entries: 0,
|
|
241
|
-
totalSize: 0,
|
|
242
|
-
hits: 0,
|
|
243
|
-
misses: 0,
|
|
244
|
-
hitRate: 0
|
|
245
|
-
};
|
|
246
|
-
} catch (error) {
|
|
247
|
-
throw new CacheOperationError(`Failed to clear cache: ${error}`, error);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* Get cache statistics.
|
|
252
|
-
*/
|
|
253
|
-
async getStats() {
|
|
254
|
-
return { ...this.stats };
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Clean up expired entries.
|
|
258
|
-
*/
|
|
259
|
-
async cleanup() {
|
|
260
|
-
this.ensureInitialized();
|
|
261
|
-
let removed = 0;
|
|
262
|
-
try {
|
|
263
|
-
const files = await (0, import_promises.readdir)(this.options.cacheDir);
|
|
264
|
-
for (const file of files) {
|
|
265
|
-
if (!file.endsWith(this.options.extension)) continue;
|
|
266
|
-
const filePath = (0, import_path.join)(this.options.cacheDir, file);
|
|
267
|
-
try {
|
|
268
|
-
const content = await (0, import_promises.readFile)(filePath, "utf8");
|
|
269
|
-
const entry = JSON.parse(content);
|
|
270
|
-
if (Date.now() > entry.metadata.expiresAt) {
|
|
271
|
-
await (0, import_promises.unlink)(filePath);
|
|
272
|
-
this.stats.entries = Math.max(0, this.stats.entries - 1);
|
|
273
|
-
this.stats.totalSize = Math.max(0, this.stats.totalSize - entry.metadata.size);
|
|
274
|
-
removed++;
|
|
275
|
-
}
|
|
276
|
-
} catch {
|
|
277
|
-
await (0, import_promises.unlink)(filePath).catch(() => {
|
|
278
|
-
});
|
|
279
|
-
removed++;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
} catch {
|
|
283
|
-
}
|
|
284
|
-
return removed;
|
|
285
|
-
}
|
|
286
|
-
/**
|
|
287
|
-
* Close the storage (no-op for filesystem).
|
|
288
|
-
*/
|
|
289
|
-
async close() {
|
|
290
|
-
}
|
|
291
|
-
/**
|
|
292
|
-
* Get the file path for a cache key.
|
|
293
|
-
* Uses SHA-256 hash to avoid collisions from key sanitization.
|
|
294
|
-
*/
|
|
295
|
-
getFilePath(key) {
|
|
296
|
-
const hash = (0, import_crypto.createHash)("sha256").update(key).digest("hex").slice(0, 16);
|
|
297
|
-
return (0, import_path.join)(this.options.cacheDir, `${hash}${this.options.extension}`);
|
|
298
|
-
}
|
|
299
|
-
/**
|
|
300
|
-
* Write a cache entry to disk.
|
|
301
|
-
*/
|
|
302
|
-
async writeEntry(filePath, entry) {
|
|
303
|
-
await (0, import_promises.mkdir)((0, import_path.dirname)(filePath), { recursive: true });
|
|
304
|
-
await (0, import_promises.writeFile)(filePath, JSON.stringify(entry, null, 2), "utf8");
|
|
305
|
-
}
|
|
306
|
-
/**
|
|
307
|
-
* Ensure the storage is initialized.
|
|
308
|
-
*/
|
|
309
|
-
ensureInitialized() {
|
|
310
|
-
if (!this.initialized) {
|
|
311
|
-
throw new StorageNotInitializedError();
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
/**
|
|
315
|
-
* Load stats from existing cache files.
|
|
316
|
-
* Reads entry metadata to get accurate manifest sizes.
|
|
317
|
-
*/
|
|
318
|
-
async loadStats() {
|
|
319
|
-
try {
|
|
320
|
-
const files = await (0, import_promises.readdir)(this.options.cacheDir);
|
|
321
|
-
let entries = 0;
|
|
322
|
-
let totalSize = 0;
|
|
323
|
-
for (const file of files) {
|
|
324
|
-
if (!file.endsWith(this.options.extension)) continue;
|
|
325
|
-
const filePath = (0, import_path.join)(this.options.cacheDir, file);
|
|
326
|
-
try {
|
|
327
|
-
const content = await (0, import_promises.readFile)(filePath, "utf8");
|
|
328
|
-
const entry = JSON.parse(content);
|
|
329
|
-
entries++;
|
|
330
|
-
totalSize += entry.metadata.size;
|
|
331
|
-
} catch {
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
this.stats.entries = entries;
|
|
335
|
-
this.stats.totalSize = totalSize;
|
|
336
|
-
} catch {
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
/**
|
|
340
|
-
* Ensure there's capacity for a new entry.
|
|
341
|
-
*/
|
|
342
|
-
async ensureCapacity(newEntrySize) {
|
|
343
|
-
if (this.stats.entries >= this.options.maxEntries) {
|
|
344
|
-
await this.evictLRU();
|
|
345
|
-
}
|
|
346
|
-
while (this.stats.totalSize + newEntrySize > this.options.maxSize) {
|
|
347
|
-
const evicted = await this.evictLRU();
|
|
348
|
-
if (!evicted) break;
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
/**
|
|
352
|
-
* Evict the least recently used entry.
|
|
353
|
-
*/
|
|
354
|
-
async evictLRU() {
|
|
355
|
-
try {
|
|
356
|
-
const files = await (0, import_promises.readdir)(this.options.cacheDir);
|
|
357
|
-
let oldestKey = null;
|
|
358
|
-
let oldestTime = Infinity;
|
|
359
|
-
let corruptedFile = null;
|
|
360
|
-
for (const file of files) {
|
|
361
|
-
if (!file.endsWith(this.options.extension)) continue;
|
|
362
|
-
const filePath = (0, import_path.join)(this.options.cacheDir, file);
|
|
363
|
-
try {
|
|
364
|
-
const content = await (0, import_promises.readFile)(filePath, "utf8");
|
|
365
|
-
const entry = JSON.parse(content);
|
|
366
|
-
if (entry.metadata.lastAccessedAt < oldestTime) {
|
|
367
|
-
oldestTime = entry.metadata.lastAccessedAt;
|
|
368
|
-
oldestKey = entry.metadata.key;
|
|
369
|
-
}
|
|
370
|
-
} catch {
|
|
371
|
-
corruptedFile = filePath;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
if (corruptedFile) {
|
|
375
|
-
try {
|
|
376
|
-
await (0, import_promises.unlink)(corruptedFile);
|
|
377
|
-
this.stats.entries = Math.max(0, this.stats.entries - 1);
|
|
378
|
-
return true;
|
|
379
|
-
} catch {
|
|
380
|
-
return false;
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
if (oldestKey) {
|
|
384
|
-
return await this.delete(oldestKey);
|
|
385
|
-
}
|
|
386
|
-
return false;
|
|
387
|
-
} catch {
|
|
388
|
-
return false;
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
/**
|
|
392
|
-
* Update hit rate statistic.
|
|
393
|
-
*/
|
|
394
|
-
updateHitRate() {
|
|
395
|
-
const total = this.stats.hits + this.stats.misses;
|
|
396
|
-
this.stats.hitRate = total > 0 ? this.stats.hits / total : 0;
|
|
397
|
-
}
|
|
398
|
-
};
|
|
399
|
-
}
|
|
400
|
-
});
|
|
401
|
-
|
|
402
|
-
// libs/ui/src/bundler/file-cache/storage/redis.ts
|
|
403
|
-
var redis_exports = {};
|
|
404
|
-
__export(redis_exports, {
|
|
405
|
-
RedisStorage: () => RedisStorage,
|
|
406
|
-
createRedisStorage: () => createRedisStorage
|
|
407
|
-
});
|
|
408
|
-
function createRedisStorage(options) {
|
|
409
|
-
return new RedisStorage(options);
|
|
410
|
-
}
|
|
411
|
-
var STATS_KEY_SUFFIX, RedisStorage;
|
|
412
|
-
var init_redis = __esm({
|
|
413
|
-
"libs/ui/src/bundler/file-cache/storage/redis.ts"() {
|
|
414
|
-
"use strict";
|
|
415
|
-
init_interface();
|
|
416
|
-
STATS_KEY_SUFFIX = ":__stats__";
|
|
417
|
-
RedisStorage = class {
|
|
418
|
-
type = "redis";
|
|
419
|
-
options;
|
|
420
|
-
initialized = false;
|
|
421
|
-
localStats = {
|
|
422
|
-
entries: 0,
|
|
423
|
-
totalSize: 0,
|
|
424
|
-
hits: 0,
|
|
425
|
-
misses: 0,
|
|
426
|
-
hitRate: 0
|
|
427
|
-
};
|
|
428
|
-
constructor(options) {
|
|
429
|
-
if (!options.client) {
|
|
430
|
-
throw new Error("Redis client is required");
|
|
431
|
-
}
|
|
432
|
-
this.options = {
|
|
433
|
-
...DEFAULT_STORAGE_OPTIONS,
|
|
434
|
-
keyPrefix: "frontmcp:ui:build:",
|
|
435
|
-
json: true,
|
|
436
|
-
...options
|
|
437
|
-
};
|
|
438
|
-
}
|
|
439
|
-
/**
|
|
440
|
-
* Initialize the Redis connection.
|
|
441
|
-
*/
|
|
442
|
-
async initialize() {
|
|
443
|
-
if (this.initialized) return;
|
|
444
|
-
try {
|
|
445
|
-
await this.options.client.ping();
|
|
446
|
-
await this.loadStats();
|
|
447
|
-
this.initialized = true;
|
|
448
|
-
} catch (error) {
|
|
449
|
-
throw new Error(`Failed to connect to Redis: ${error}`);
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
/**
|
|
453
|
-
* Get a cached manifest.
|
|
454
|
-
*/
|
|
455
|
-
async get(key) {
|
|
456
|
-
this.ensureInitialized();
|
|
457
|
-
const redisKey = this.getRedisKey(key);
|
|
458
|
-
try {
|
|
459
|
-
const data = await this.options.client.get(redisKey);
|
|
460
|
-
if (!data) {
|
|
461
|
-
this.localStats.misses++;
|
|
462
|
-
this.updateHitRate();
|
|
463
|
-
await this.persistStats();
|
|
464
|
-
return void 0;
|
|
465
|
-
}
|
|
466
|
-
const entry = JSON.parse(data);
|
|
467
|
-
entry.metadata.lastAccessedAt = Date.now();
|
|
468
|
-
entry.metadata.accessCount++;
|
|
469
|
-
const ttl = await this.options.client.ttl(redisKey);
|
|
470
|
-
if (ttl > 0) {
|
|
471
|
-
const serialized = JSON.stringify(entry);
|
|
472
|
-
await this.options.client.setex(redisKey, ttl, serialized);
|
|
473
|
-
}
|
|
474
|
-
this.localStats.hits++;
|
|
475
|
-
this.updateHitRate();
|
|
476
|
-
await this.persistStats();
|
|
477
|
-
return entry.data;
|
|
478
|
-
} catch (error) {
|
|
479
|
-
console.warn?.(`Redis cache get failed for key "${key}": ${error}`);
|
|
480
|
-
this.localStats.misses++;
|
|
481
|
-
this.updateHitRate();
|
|
482
|
-
await this.persistStats().catch(() => {
|
|
483
|
-
});
|
|
484
|
-
return void 0;
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
/**
|
|
488
|
-
* Store a manifest in cache.
|
|
489
|
-
*/
|
|
490
|
-
async set(key, manifest, ttl) {
|
|
491
|
-
this.ensureInitialized();
|
|
492
|
-
const redisKey = this.getRedisKey(key);
|
|
493
|
-
const size = calculateManifestSize(manifest);
|
|
494
|
-
const effectiveTtl = ttl ?? this.options.defaultTtl;
|
|
495
|
-
const entry = {
|
|
496
|
-
data: manifest,
|
|
497
|
-
metadata: {
|
|
498
|
-
key,
|
|
499
|
-
size,
|
|
500
|
-
createdAt: Date.now(),
|
|
501
|
-
expiresAt: Date.now() + effectiveTtl * 1e3,
|
|
502
|
-
lastAccessedAt: Date.now(),
|
|
503
|
-
accessCount: 0
|
|
504
|
-
}
|
|
505
|
-
};
|
|
506
|
-
const serialized = JSON.stringify(entry);
|
|
507
|
-
await this.options.client.setex(redisKey, effectiveTtl, serialized);
|
|
508
|
-
this.localStats.entries++;
|
|
509
|
-
this.localStats.totalSize += size;
|
|
510
|
-
await this.persistStats();
|
|
511
|
-
}
|
|
512
|
-
/**
|
|
513
|
-
* Check if a key exists.
|
|
514
|
-
*/
|
|
515
|
-
async has(key) {
|
|
516
|
-
this.ensureInitialized();
|
|
517
|
-
const redisKey = this.getRedisKey(key);
|
|
518
|
-
const exists = await this.options.client.exists(redisKey);
|
|
519
|
-
return exists > 0;
|
|
520
|
-
}
|
|
521
|
-
/**
|
|
522
|
-
* Delete a cached entry.
|
|
523
|
-
*/
|
|
524
|
-
async delete(key) {
|
|
525
|
-
this.ensureInitialized();
|
|
526
|
-
const redisKey = this.getRedisKey(key);
|
|
527
|
-
try {
|
|
528
|
-
const data = await this.options.client.get(redisKey);
|
|
529
|
-
if (data) {
|
|
530
|
-
const entry = JSON.parse(data);
|
|
531
|
-
this.localStats.totalSize = Math.max(0, this.localStats.totalSize - entry.metadata.size);
|
|
532
|
-
}
|
|
533
|
-
} catch {
|
|
534
|
-
}
|
|
535
|
-
const deleted = await this.options.client.del(redisKey);
|
|
536
|
-
if (deleted > 0) {
|
|
537
|
-
this.localStats.entries = Math.max(0, this.localStats.entries - 1);
|
|
538
|
-
await this.persistStats();
|
|
539
|
-
return true;
|
|
540
|
-
}
|
|
541
|
-
return false;
|
|
542
|
-
}
|
|
543
|
-
/**
|
|
544
|
-
* Clear all cached entries.
|
|
545
|
-
*/
|
|
546
|
-
async clear() {
|
|
547
|
-
this.ensureInitialized();
|
|
548
|
-
const pattern = `${this.options.keyPrefix}*`;
|
|
549
|
-
const keys = await this.options.client.keys(pattern);
|
|
550
|
-
if (keys.length > 0) {
|
|
551
|
-
await this.options.client.del(keys);
|
|
552
|
-
}
|
|
553
|
-
this.localStats = {
|
|
554
|
-
entries: 0,
|
|
555
|
-
totalSize: 0,
|
|
556
|
-
hits: 0,
|
|
557
|
-
misses: 0,
|
|
558
|
-
hitRate: 0
|
|
559
|
-
};
|
|
560
|
-
await this.persistStats();
|
|
561
|
-
}
|
|
562
|
-
/**
|
|
563
|
-
* Get cache statistics.
|
|
564
|
-
*/
|
|
565
|
-
async getStats() {
|
|
566
|
-
await this.loadStats();
|
|
567
|
-
return { ...this.localStats };
|
|
568
|
-
}
|
|
569
|
-
/**
|
|
570
|
-
* Clean up expired entries.
|
|
571
|
-
* Redis handles TTL expiration automatically, so this just refreshes stats.
|
|
572
|
-
*/
|
|
573
|
-
async cleanup() {
|
|
574
|
-
this.ensureInitialized();
|
|
575
|
-
const pattern = `${this.options.keyPrefix}*`;
|
|
576
|
-
const keys = await this.options.client.keys(pattern);
|
|
577
|
-
const dataKeys = keys.filter((k) => !k.endsWith(STATS_KEY_SUFFIX));
|
|
578
|
-
const previousCount = this.localStats.entries;
|
|
579
|
-
this.localStats.entries = dataKeys.length;
|
|
580
|
-
let totalSize = 0;
|
|
581
|
-
for (const key of dataKeys) {
|
|
582
|
-
try {
|
|
583
|
-
const data = await this.options.client.get(key);
|
|
584
|
-
if (data) {
|
|
585
|
-
const entry = JSON.parse(data);
|
|
586
|
-
totalSize += entry.metadata.size;
|
|
587
|
-
}
|
|
588
|
-
} catch {
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
this.localStats.totalSize = totalSize;
|
|
592
|
-
await this.persistStats();
|
|
593
|
-
return Math.max(0, previousCount - this.localStats.entries);
|
|
594
|
-
}
|
|
595
|
-
/**
|
|
596
|
-
* Close the Redis connection.
|
|
597
|
-
*/
|
|
598
|
-
async close() {
|
|
599
|
-
await this.options.client.quit();
|
|
600
|
-
}
|
|
601
|
-
/**
|
|
602
|
-
* Get the Redis key for a cache key.
|
|
603
|
-
*/
|
|
604
|
-
getRedisKey(key) {
|
|
605
|
-
return `${this.options.keyPrefix}${key}`;
|
|
606
|
-
}
|
|
607
|
-
/**
|
|
608
|
-
* Get the Redis key for stats.
|
|
609
|
-
*/
|
|
610
|
-
getStatsKey() {
|
|
611
|
-
return `${this.options.keyPrefix}${STATS_KEY_SUFFIX}`;
|
|
612
|
-
}
|
|
613
|
-
/**
|
|
614
|
-
* Ensure the storage is initialized.
|
|
615
|
-
*/
|
|
616
|
-
ensureInitialized() {
|
|
617
|
-
if (!this.initialized) {
|
|
618
|
-
throw new Error("Storage not initialized. Call initialize() first.");
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
/**
|
|
622
|
-
* Load stats from Redis.
|
|
623
|
-
*/
|
|
624
|
-
async loadStats() {
|
|
625
|
-
try {
|
|
626
|
-
const statsKey = this.getStatsKey();
|
|
627
|
-
const data = await this.options.client.get(statsKey);
|
|
628
|
-
if (data) {
|
|
629
|
-
const savedStats = JSON.parse(data);
|
|
630
|
-
this.localStats = {
|
|
631
|
-
...this.localStats,
|
|
632
|
-
...savedStats
|
|
633
|
-
};
|
|
634
|
-
}
|
|
635
|
-
} catch {
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
/**
|
|
639
|
-
* Persist stats to Redis.
|
|
640
|
-
*/
|
|
641
|
-
async persistStats() {
|
|
642
|
-
try {
|
|
643
|
-
const statsKey = this.getStatsKey();
|
|
644
|
-
const serialized = JSON.stringify(this.localStats);
|
|
645
|
-
await this.options.client.set(statsKey, serialized);
|
|
646
|
-
} catch {
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
/**
|
|
650
|
-
* Update hit rate statistic.
|
|
651
|
-
*/
|
|
652
|
-
updateHitRate() {
|
|
653
|
-
const total = this.localStats.hits + this.localStats.misses;
|
|
654
|
-
this.localStats.hitRate = total > 0 ? this.localStats.hits / total : 0;
|
|
655
|
-
}
|
|
656
|
-
};
|
|
657
|
-
}
|
|
658
|
-
});
|
|
659
|
-
|
|
660
30
|
// libs/ui/src/bundler/index.ts
|
|
661
31
|
var bundler_exports = {};
|
|
662
32
|
__export(bundler_exports, {
|
|
663
|
-
|
|
664
|
-
|
|
33
|
+
ALL_PLATFORMS: () => ALL_PLATFORMS,
|
|
34
|
+
BundlerCache: () => import_bundler4.BundlerCache,
|
|
35
|
+
ComponentBuilder: () => import_bundler7.ComponentBuilder,
|
|
665
36
|
DEFAULT_BUNDLER_OPTIONS: () => DEFAULT_BUNDLER_OPTIONS,
|
|
666
37
|
DEFAULT_BUNDLE_OPTIONS: () => DEFAULT_BUNDLE_OPTIONS,
|
|
667
38
|
DEFAULT_SECURITY_POLICY: () => DEFAULT_SECURITY_POLICY,
|
|
668
39
|
DEFAULT_STATIC_HTML_OPTIONS: () => DEFAULT_STATIC_HTML_OPTIONS,
|
|
669
|
-
DEFAULT_STORAGE_OPTIONS: () => DEFAULT_STORAGE_OPTIONS,
|
|
670
|
-
ExecutionError: () => ExecutionError,
|
|
671
|
-
FilesystemStorage: () => FilesystemStorage,
|
|
40
|
+
DEFAULT_STORAGE_OPTIONS: () => import_bundler7.DEFAULT_STORAGE_OPTIONS,
|
|
41
|
+
ExecutionError: () => import_bundler2.ExecutionError,
|
|
42
|
+
FilesystemStorage: () => import_bundler7.FilesystemStorage,
|
|
43
|
+
HYBRID_DATA_PLACEHOLDER: () => HYBRID_DATA_PLACEHOLDER,
|
|
44
|
+
HYBRID_INPUT_PLACEHOLDER: () => HYBRID_INPUT_PLACEHOLDER,
|
|
672
45
|
InMemoryBundler: () => InMemoryBundler,
|
|
673
|
-
RedisStorage: () => RedisStorage,
|
|
46
|
+
RedisStorage: () => import_bundler7.RedisStorage,
|
|
674
47
|
STATIC_HTML_CDN: () => STATIC_HTML_CDN,
|
|
675
|
-
SecurityError: () => SecurityError,
|
|
676
|
-
buildIdFromHash: () => buildIdFromHash,
|
|
677
|
-
calculateComponentHash: () => calculateComponentHash,
|
|
678
|
-
calculateManifestSize: () => calculateManifestSize,
|
|
679
|
-
calculateQuickHash: () => calculateQuickHash,
|
|
48
|
+
SecurityError: () => import_bundler2.SecurityError,
|
|
49
|
+
buildIdFromHash: () => import_bundler7.buildIdFromHash,
|
|
50
|
+
calculateComponentHash: () => import_bundler7.calculateComponentHash,
|
|
51
|
+
calculateManifestSize: () => import_bundler7.calculateManifestSize,
|
|
52
|
+
calculateQuickHash: () => import_bundler7.calculateQuickHash,
|
|
680
53
|
createBundler: () => createBundler,
|
|
681
|
-
createCacheKey: () => createCacheKey,
|
|
682
|
-
createFilesystemBuilder: () => createFilesystemBuilder,
|
|
683
|
-
createFilesystemStorage: () => createFilesystemStorage,
|
|
684
|
-
createRedisBuilder: () => createRedisBuilder,
|
|
685
|
-
createRedisStorage: () => createRedisStorage,
|
|
686
|
-
executeCode: () => executeCode,
|
|
687
|
-
executeDefault: () => executeDefault,
|
|
688
|
-
generateBuildId: () => generateBuildId,
|
|
54
|
+
createCacheKey: () => import_bundler4.createCacheKey,
|
|
55
|
+
createFilesystemBuilder: () => import_bundler7.createFilesystemBuilder,
|
|
56
|
+
createFilesystemStorage: () => import_bundler7.createFilesystemStorage,
|
|
57
|
+
createRedisBuilder: () => import_bundler7.createRedisBuilder,
|
|
58
|
+
createRedisStorage: () => import_bundler7.createRedisStorage,
|
|
59
|
+
executeCode: () => import_bundler6.executeCode,
|
|
60
|
+
executeDefault: () => import_bundler6.executeDefault,
|
|
61
|
+
generateBuildId: () => import_bundler7.generateBuildId,
|
|
689
62
|
getCdnTypeForPlatform: () => getCdnTypeForPlatform,
|
|
690
|
-
hashContent: () => hashContent,
|
|
691
|
-
hashFile: () => hashFile,
|
|
692
|
-
hashFiles: () => hashFiles,
|
|
693
|
-
isExecutionError: () => isExecutionError,
|
|
694
|
-
mergePolicy: () => mergePolicy,
|
|
695
|
-
sha256: () => sha256,
|
|
696
|
-
sha256Buffer: () => sha256Buffer,
|
|
697
|
-
throwOnViolations: () => throwOnViolations,
|
|
698
|
-
validateImports: () => validateImports,
|
|
699
|
-
validateSize: () => validateSize,
|
|
700
|
-
validateSource: () => validateSource
|
|
63
|
+
hashContent: () => import_bundler4.hashContent,
|
|
64
|
+
hashFile: () => import_bundler7.hashFile,
|
|
65
|
+
hashFiles: () => import_bundler7.hashFiles,
|
|
66
|
+
isExecutionError: () => import_bundler6.isExecutionError,
|
|
67
|
+
mergePolicy: () => import_bundler5.mergePolicy,
|
|
68
|
+
sha256: () => import_bundler7.sha256,
|
|
69
|
+
sha256Buffer: () => import_bundler7.sha256Buffer,
|
|
70
|
+
throwOnViolations: () => import_bundler5.throwOnViolations,
|
|
71
|
+
validateImports: () => import_bundler5.validateImports,
|
|
72
|
+
validateSize: () => import_bundler5.validateSize,
|
|
73
|
+
validateSource: () => import_bundler5.validateSource
|
|
701
74
|
});
|
|
702
75
|
module.exports = __toCommonJS(bundler_exports);
|
|
703
76
|
|
|
704
77
|
// libs/ui/src/bundler/types.ts
|
|
78
|
+
var HYBRID_DATA_PLACEHOLDER = "__FRONTMCP_OUTPUT_PLACEHOLDER__";
|
|
79
|
+
var HYBRID_INPUT_PLACEHOLDER = "__FRONTMCP_INPUT_PLACEHOLDER__";
|
|
705
80
|
var DEFAULT_SECURITY_POLICY = {
|
|
706
81
|
allowedImports: [/^react$/, /^react-dom$/, /^react\/jsx-runtime$/, /^react\/jsx-dev-runtime$/, /^@frontmcp\/ui/],
|
|
707
82
|
blockedImports: [
|
|
@@ -814,6 +189,13 @@ var DEFAULT_BUNDLER_OPTIONS = {
|
|
|
814
189
|
verbose: false,
|
|
815
190
|
esbuildOptions: {}
|
|
816
191
|
};
|
|
192
|
+
var ALL_PLATFORMS = [
|
|
193
|
+
"openai",
|
|
194
|
+
"claude",
|
|
195
|
+
"cursor",
|
|
196
|
+
"ext-apps",
|
|
197
|
+
"generic"
|
|
198
|
+
];
|
|
817
199
|
var STATIC_HTML_CDN = {
|
|
818
200
|
/**
|
|
819
201
|
* ES modules from esm.sh (React 19, modern platforms)
|
|
@@ -829,11 +211,6 @@ var STATIC_HTML_CDN = {
|
|
|
829
211
|
react: "https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js",
|
|
830
212
|
reactDom: "https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"
|
|
831
213
|
},
|
|
832
|
-
/**
|
|
833
|
-
* Tailwind CSS from cdnjs (cloudflare) - works on all platforms
|
|
834
|
-
* Using CSS file instead of JS browser version to avoid style normalization issues
|
|
835
|
-
*/
|
|
836
|
-
tailwind: "https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/3.4.1/tailwind.min.css",
|
|
837
214
|
/**
|
|
838
215
|
* Font CDN URLs
|
|
839
216
|
*/
|
|
@@ -863,656 +240,63 @@ var DEFAULT_STATIC_HTML_OPTIONS = {
|
|
|
863
240
|
universal: false,
|
|
864
241
|
contentType: "auto",
|
|
865
242
|
includeMarkdown: false,
|
|
866
|
-
includeMdx: false
|
|
243
|
+
includeMdx: false,
|
|
244
|
+
// Build mode defaults
|
|
245
|
+
buildMode: "static"
|
|
867
246
|
};
|
|
868
247
|
|
|
869
|
-
// libs/ui/src/bundler/
|
|
870
|
-
var
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
hits: 0,
|
|
875
|
-
misses: 0,
|
|
876
|
-
evictions: 0
|
|
877
|
-
};
|
|
878
|
-
constructor(options = {}) {
|
|
879
|
-
this.options = {
|
|
880
|
-
maxSize: options.maxSize ?? 100,
|
|
881
|
-
ttl: options.ttl ?? 3e5
|
|
882
|
-
};
|
|
883
|
-
}
|
|
884
|
-
/**
|
|
885
|
-
* Get a cached bundle result.
|
|
886
|
-
*
|
|
887
|
-
* @param key - Cache key (typically content hash)
|
|
888
|
-
* @returns Cached result or undefined if not found/expired
|
|
889
|
-
*/
|
|
890
|
-
get(key) {
|
|
891
|
-
const entry = this.cache.get(key);
|
|
892
|
-
if (!entry) {
|
|
893
|
-
this.stats.misses++;
|
|
894
|
-
return void 0;
|
|
895
|
-
}
|
|
896
|
-
if (this.isExpired(entry)) {
|
|
897
|
-
this.cache.delete(key);
|
|
898
|
-
this.stats.misses++;
|
|
899
|
-
this.stats.evictions++;
|
|
900
|
-
return void 0;
|
|
901
|
-
}
|
|
902
|
-
entry.lastAccessedAt = Date.now();
|
|
903
|
-
entry.accessCount++;
|
|
904
|
-
this.stats.hits++;
|
|
905
|
-
this.cache.delete(key);
|
|
906
|
-
this.cache.set(key, entry);
|
|
907
|
-
return entry.result;
|
|
908
|
-
}
|
|
909
|
-
/**
|
|
910
|
-
* Store a bundle result in the cache.
|
|
911
|
-
*
|
|
912
|
-
* @param key - Cache key (typically content hash)
|
|
913
|
-
* @param result - Bundle result to cache
|
|
914
|
-
*/
|
|
915
|
-
set(key, result) {
|
|
916
|
-
while (this.cache.size >= this.options.maxSize) {
|
|
917
|
-
this.evictOldest();
|
|
918
|
-
}
|
|
919
|
-
const now = Date.now();
|
|
920
|
-
const entry = {
|
|
921
|
-
result,
|
|
922
|
-
createdAt: now,
|
|
923
|
-
lastAccessedAt: now,
|
|
924
|
-
accessCount: 1
|
|
925
|
-
};
|
|
926
|
-
this.cache.set(key, entry);
|
|
927
|
-
}
|
|
928
|
-
/**
|
|
929
|
-
* Check if a key exists in the cache (and is not expired).
|
|
930
|
-
*
|
|
931
|
-
* @param key - Cache key to check
|
|
932
|
-
* @returns true if key exists and is not expired
|
|
933
|
-
*/
|
|
934
|
-
has(key) {
|
|
935
|
-
const entry = this.cache.get(key);
|
|
936
|
-
if (!entry) return false;
|
|
937
|
-
if (this.isExpired(entry)) {
|
|
938
|
-
this.cache.delete(key);
|
|
939
|
-
this.stats.evictions++;
|
|
940
|
-
return false;
|
|
941
|
-
}
|
|
942
|
-
return true;
|
|
943
|
-
}
|
|
944
|
-
/**
|
|
945
|
-
* Delete a specific entry from the cache.
|
|
946
|
-
*
|
|
947
|
-
* @param key - Cache key to delete
|
|
948
|
-
* @returns true if the key was found and deleted
|
|
949
|
-
*/
|
|
950
|
-
delete(key) {
|
|
951
|
-
return this.cache.delete(key);
|
|
952
|
-
}
|
|
953
|
-
/**
|
|
954
|
-
* Clear all entries from the cache.
|
|
955
|
-
*/
|
|
956
|
-
clear() {
|
|
957
|
-
this.cache.clear();
|
|
958
|
-
this.stats = {
|
|
959
|
-
hits: 0,
|
|
960
|
-
misses: 0,
|
|
961
|
-
evictions: 0
|
|
962
|
-
};
|
|
963
|
-
}
|
|
964
|
-
/**
|
|
965
|
-
* Get cache statistics.
|
|
966
|
-
*
|
|
967
|
-
* @returns Current cache statistics
|
|
968
|
-
*/
|
|
969
|
-
getStats() {
|
|
970
|
-
const total = this.stats.hits + this.stats.misses;
|
|
971
|
-
const hitRate = total > 0 ? this.stats.hits / total : 0;
|
|
972
|
-
let memoryUsage = 0;
|
|
973
|
-
for (const entry of this.cache.values()) {
|
|
974
|
-
memoryUsage += entry.result.size;
|
|
975
|
-
if (entry.result.map) {
|
|
976
|
-
memoryUsage += entry.result.map.length;
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
return {
|
|
980
|
-
size: this.cache.size,
|
|
981
|
-
hits: this.stats.hits,
|
|
982
|
-
misses: this.stats.misses,
|
|
983
|
-
hitRate,
|
|
984
|
-
evictions: this.stats.evictions,
|
|
985
|
-
memoryUsage
|
|
986
|
-
};
|
|
987
|
-
}
|
|
988
|
-
/**
|
|
989
|
-
* Remove expired entries from the cache.
|
|
990
|
-
*
|
|
991
|
-
* @returns Number of entries removed
|
|
992
|
-
*/
|
|
993
|
-
cleanup() {
|
|
994
|
-
let removed = 0;
|
|
995
|
-
for (const [key, entry] of this.cache.entries()) {
|
|
996
|
-
if (this.isExpired(entry)) {
|
|
997
|
-
this.cache.delete(key);
|
|
998
|
-
removed++;
|
|
999
|
-
}
|
|
1000
|
-
}
|
|
1001
|
-
this.stats.evictions += removed;
|
|
1002
|
-
return removed;
|
|
1003
|
-
}
|
|
1004
|
-
/**
|
|
1005
|
-
* Get all cache keys.
|
|
1006
|
-
*
|
|
1007
|
-
* @returns Array of cache keys
|
|
1008
|
-
*/
|
|
1009
|
-
keys() {
|
|
1010
|
-
return Array.from(this.cache.keys());
|
|
1011
|
-
}
|
|
1012
|
-
/**
|
|
1013
|
-
* Get the number of entries in the cache.
|
|
1014
|
-
*/
|
|
1015
|
-
get size() {
|
|
1016
|
-
return this.cache.size;
|
|
1017
|
-
}
|
|
1018
|
-
/**
|
|
1019
|
-
* Check if an entry is expired.
|
|
1020
|
-
*/
|
|
1021
|
-
isExpired(entry) {
|
|
1022
|
-
return Date.now() - entry.createdAt > this.options.ttl;
|
|
1023
|
-
}
|
|
1024
|
-
/**
|
|
1025
|
-
* Evict the oldest (least recently used) entry.
|
|
1026
|
-
*/
|
|
1027
|
-
evictOldest() {
|
|
1028
|
-
const oldestKey = this.cache.keys().next().value;
|
|
1029
|
-
if (oldestKey !== void 0) {
|
|
1030
|
-
this.cache.delete(oldestKey);
|
|
1031
|
-
this.stats.evictions++;
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
};
|
|
1035
|
-
function hashContent(content) {
|
|
1036
|
-
let hash = 2166136261;
|
|
1037
|
-
for (let i = 0; i < content.length; i++) {
|
|
1038
|
-
hash ^= content.charCodeAt(i);
|
|
1039
|
-
hash = Math.imul(hash, 16777619);
|
|
1040
|
-
}
|
|
1041
|
-
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
1042
|
-
}
|
|
1043
|
-
function createCacheKey(source, options) {
|
|
1044
|
-
const sourceHash = hashContent(source);
|
|
1045
|
-
const optionsHash = hashContent(
|
|
1046
|
-
JSON.stringify({
|
|
1047
|
-
sourceType: options.sourceType,
|
|
1048
|
-
format: options.format,
|
|
1049
|
-
minify: options.minify,
|
|
1050
|
-
externals: options.externals?.sort(),
|
|
1051
|
-
target: options.target
|
|
1052
|
-
})
|
|
1053
|
-
);
|
|
1054
|
-
return `${sourceHash}-${optionsHash}`;
|
|
1055
|
-
}
|
|
248
|
+
// libs/ui/src/bundler/bundler.ts
|
|
249
|
+
var import_adapters = require("@frontmcp/uipack/adapters");
|
|
250
|
+
var import_theme = require("@frontmcp/uipack/theme");
|
|
251
|
+
var import_bundler = require("@frontmcp/uipack/bundler");
|
|
252
|
+
var import_utils = require("@frontmcp/uipack/utils");
|
|
1056
253
|
|
|
1057
|
-
// libs/ui/src/
|
|
1058
|
-
var
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
processEnv: /\bprocess\.env\b/g,
|
|
1064
|
-
globalThis: /\bglobalThis\b/g,
|
|
1065
|
-
windowLocation: /\bwindow\.location\b/g,
|
|
1066
|
-
documentCookie: /\bdocument\.cookie\b/g,
|
|
1067
|
-
innerHTML: /\.innerHTML\s*=/g,
|
|
1068
|
-
outerHTML: /\.outerHTML\s*=/g,
|
|
1069
|
-
document_write: /\bdocument\.write\s*\(/g
|
|
1070
|
-
};
|
|
1071
|
-
function validateSource(source, policy = DEFAULT_SECURITY_POLICY) {
|
|
1072
|
-
const violations = [];
|
|
1073
|
-
if (policy.noEval !== false) {
|
|
1074
|
-
const evalMatches = [...source.matchAll(UNSAFE_PATTERNS.eval)];
|
|
1075
|
-
for (const match of evalMatches) {
|
|
1076
|
-
violations.push({
|
|
1077
|
-
type: "eval-usage",
|
|
1078
|
-
message: "eval() is not allowed for security reasons",
|
|
1079
|
-
location: getLocation(source, match.index ?? 0),
|
|
1080
|
-
value: match[0]
|
|
1081
|
-
});
|
|
1082
|
-
}
|
|
1083
|
-
const fnMatches = [...source.matchAll(UNSAFE_PATTERNS.functionConstructor)];
|
|
1084
|
-
for (const match of fnMatches) {
|
|
1085
|
-
violations.push({
|
|
1086
|
-
type: "eval-usage",
|
|
1087
|
-
message: "new Function() is not allowed for security reasons",
|
|
1088
|
-
location: getLocation(source, match.index ?? 0),
|
|
1089
|
-
value: match[0]
|
|
1090
|
-
});
|
|
1091
|
-
}
|
|
1092
|
-
}
|
|
1093
|
-
if (policy.noDynamicImports !== false) {
|
|
1094
|
-
const matches = [...source.matchAll(UNSAFE_PATTERNS.dynamicImport)];
|
|
1095
|
-
for (const match of matches) {
|
|
1096
|
-
violations.push({
|
|
1097
|
-
type: "dynamic-import",
|
|
1098
|
-
message: "Dynamic imports are not allowed for security reasons",
|
|
1099
|
-
location: getLocation(source, match.index ?? 0),
|
|
1100
|
-
value: match[0]
|
|
1101
|
-
});
|
|
1102
|
-
}
|
|
1103
|
-
}
|
|
1104
|
-
if (policy.noRequire !== false) {
|
|
1105
|
-
const matches = [...source.matchAll(UNSAFE_PATTERNS.require)];
|
|
1106
|
-
for (const match of matches) {
|
|
1107
|
-
violations.push({
|
|
1108
|
-
type: "require-usage",
|
|
1109
|
-
message: "require() is not allowed for security reasons",
|
|
1110
|
-
location: getLocation(source, match.index ?? 0),
|
|
1111
|
-
value: match[0]
|
|
1112
|
-
});
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1115
|
-
const importViolations = validateImports(source, policy);
|
|
1116
|
-
violations.push(...importViolations);
|
|
1117
|
-
return violations;
|
|
1118
|
-
}
|
|
1119
|
-
function validateImports(source, policy = DEFAULT_SECURITY_POLICY) {
|
|
1120
|
-
const violations = [];
|
|
1121
|
-
const importPattern = /import\s+(?:(?:\{[^}]*\}|[\w*]+)\s+from\s+)?['"]([^'"]+)['"]/g;
|
|
1122
|
-
const imports = [];
|
|
1123
|
-
let match;
|
|
1124
|
-
while ((match = importPattern.exec(source)) !== null) {
|
|
1125
|
-
imports.push({ module: match[1], index: match.index });
|
|
254
|
+
// libs/ui/src/universal/types.ts
|
|
255
|
+
var UNIVERSAL_CDN = {
|
|
256
|
+
esm: {
|
|
257
|
+
reactMarkdown: "https://esm.sh/react-markdown@9",
|
|
258
|
+
mdxReact: "https://esm.sh/@mdx-js/react@3",
|
|
259
|
+
remarkGfm: "https://esm.sh/remark-gfm@4"
|
|
1126
260
|
}
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
261
|
+
// Note: These libraries are not available on cdnjs
|
|
262
|
+
// For Claude, we use inline implementations
|
|
263
|
+
};
|
|
264
|
+
function detectContentType(source) {
|
|
265
|
+
if (typeof source === "function") {
|
|
266
|
+
return "react";
|
|
1130
267
|
}
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
for (const blocked of policy.blockedImports) {
|
|
1134
|
-
if (blocked.test(imp.module)) {
|
|
1135
|
-
violations.push({
|
|
1136
|
-
type: "blocked-import",
|
|
1137
|
-
message: `Import '${imp.module}' is blocked by security policy`,
|
|
1138
|
-
location: getLocation(source, imp.index),
|
|
1139
|
-
value: imp.module
|
|
1140
|
-
});
|
|
1141
|
-
break;
|
|
1142
|
-
}
|
|
1143
|
-
}
|
|
1144
|
-
}
|
|
1145
|
-
if (policy.allowedImports && policy.allowedImports.length > 0) {
|
|
1146
|
-
const isAllowed = policy.allowedImports.some((pattern) => pattern.test(imp.module));
|
|
1147
|
-
if (!isAllowed) {
|
|
1148
|
-
const alreadyBlocked = violations.some((v) => v.type === "blocked-import" && v.value === imp.module);
|
|
1149
|
-
if (!alreadyBlocked) {
|
|
1150
|
-
violations.push({
|
|
1151
|
-
type: "disallowed-import",
|
|
1152
|
-
message: `Import '${imp.module}' is not in the allowed imports list`,
|
|
1153
|
-
location: getLocation(source, imp.index),
|
|
1154
|
-
value: imp.module
|
|
1155
|
-
});
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
268
|
+
if (typeof source !== "string") {
|
|
269
|
+
return "html";
|
|
1159
270
|
}
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
const
|
|
1164
|
-
if (
|
|
1165
|
-
return
|
|
1166
|
-
type: "size-exceeded",
|
|
1167
|
-
message: `Bundle size (${formatBytes(size)}) exceeds maximum allowed (${formatBytes(maxSize)})`,
|
|
1168
|
-
value: String(size)
|
|
1169
|
-
};
|
|
271
|
+
const hasModuleSyntax = /^import\s+/m.test(source) || /^export\s+(default\s+)?/m.test(source) || /^const\s+\w+\s*=\s*\([^)]*\)\s*=>/m.test(source) || // Arrow function components
|
|
272
|
+
/^function\s+\w+\s*\(/m.test(source);
|
|
273
|
+
const hasJsxTags = /<[A-Z][a-zA-Z]*/.test(source);
|
|
274
|
+
const hasMarkdown = /^#{1,6}\s/m.test(source) || /^\*\s/m.test(source) || /^-\s/m.test(source) || /^\d+\.\s/m.test(source);
|
|
275
|
+
if (hasModuleSyntax && hasJsxTags) {
|
|
276
|
+
return "react";
|
|
1170
277
|
}
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
function mergePolicy(userPolicy) {
|
|
1174
|
-
if (!userPolicy) {
|
|
1175
|
-
return { ...DEFAULT_SECURITY_POLICY };
|
|
278
|
+
if (hasJsxTags && hasMarkdown && !hasModuleSyntax) {
|
|
279
|
+
return "mdx";
|
|
1176
280
|
}
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
blockedImports: userPolicy.blockedImports ?? DEFAULT_SECURITY_POLICY.blockedImports,
|
|
1180
|
-
maxBundleSize: userPolicy.maxBundleSize ?? DEFAULT_SECURITY_POLICY.maxBundleSize,
|
|
1181
|
-
maxTransformTime: userPolicy.maxTransformTime ?? DEFAULT_SECURITY_POLICY.maxTransformTime,
|
|
1182
|
-
noEval: userPolicy.noEval ?? DEFAULT_SECURITY_POLICY.noEval,
|
|
1183
|
-
noDynamicImports: userPolicy.noDynamicImports ?? DEFAULT_SECURITY_POLICY.noDynamicImports,
|
|
1184
|
-
noRequire: userPolicy.noRequire ?? DEFAULT_SECURITY_POLICY.noRequire,
|
|
1185
|
-
allowedGlobals: userPolicy.allowedGlobals ?? DEFAULT_SECURITY_POLICY.allowedGlobals
|
|
1186
|
-
};
|
|
1187
|
-
}
|
|
1188
|
-
function getLocation(source, index) {
|
|
1189
|
-
const lines = source.slice(0, index).split("\n");
|
|
1190
|
-
return {
|
|
1191
|
-
line: lines.length,
|
|
1192
|
-
column: lines[lines.length - 1].length + 1
|
|
1193
|
-
};
|
|
1194
|
-
}
|
|
1195
|
-
function formatBytes(bytes) {
|
|
1196
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
1197
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
1198
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
1199
|
-
}
|
|
1200
|
-
var SecurityError = class extends Error {
|
|
1201
|
-
violations;
|
|
1202
|
-
constructor(message, violations) {
|
|
1203
|
-
super(message);
|
|
1204
|
-
this.name = "SecurityError";
|
|
1205
|
-
this.violations = violations;
|
|
281
|
+
if (hasMarkdown || /\*\*[^*]+\*\*/.test(source) || /\[[^\]]+\]\([^)]+\)/.test(source)) {
|
|
282
|
+
return "markdown";
|
|
1206
283
|
}
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
if (violations.length > 0) {
|
|
1210
|
-
const message = violations.map((v) => v.message).join("; ");
|
|
1211
|
-
throw new SecurityError(`Security policy violation: ${message}`, violations);
|
|
284
|
+
if (hasJsxTags && !hasModuleSyntax) {
|
|
285
|
+
return "mdx";
|
|
1212
286
|
}
|
|
287
|
+
return "html";
|
|
1213
288
|
}
|
|
1214
289
|
|
|
1215
|
-
// libs/ui/src/
|
|
1216
|
-
var
|
|
1217
|
-
var
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
function mapSecurityLevel(policy) {
|
|
1226
|
-
if (policy?.blockedImports && policy.blockedImports.length > STRICT_SECURITY_BLOCKED_IMPORTS_THRESHOLD) {
|
|
1227
|
-
return "STRICT";
|
|
1228
|
-
}
|
|
1229
|
-
return "SECURE";
|
|
1230
|
-
}
|
|
1231
|
-
function createJSXRuntime(React) {
|
|
1232
|
-
const R = React;
|
|
1233
|
-
return {
|
|
1234
|
-
jsx: (type, props, key) => {
|
|
1235
|
-
const { children, ...rest } = props;
|
|
1236
|
-
return R.createElement(type, key ? { ...rest, key } : rest, children);
|
|
1237
|
-
},
|
|
1238
|
-
jsxs: (type, props, key) => {
|
|
1239
|
-
const { children, ...rest } = props;
|
|
1240
|
-
return R.createElement(type, key ? { ...rest, key } : rest, children);
|
|
1241
|
-
},
|
|
1242
|
-
jsxDEV: (type, props, key, _isStaticChildren, _source, _self) => {
|
|
1243
|
-
const { children, ...rest } = props;
|
|
1244
|
-
return R.createElement(type, key ? { ...rest, key } : rest, children);
|
|
1245
|
-
},
|
|
1246
|
-
Fragment: R.Fragment
|
|
1247
|
-
};
|
|
1248
|
-
}
|
|
1249
|
-
var DANGEROUS_GLOBAL_KEYS = /* @__PURE__ */ new Set([
|
|
1250
|
-
"process",
|
|
1251
|
-
"require",
|
|
1252
|
-
"__dirname",
|
|
1253
|
-
"__filename",
|
|
1254
|
-
"Buffer",
|
|
1255
|
-
"eval",
|
|
1256
|
-
"Function",
|
|
1257
|
-
"constructor",
|
|
1258
|
-
"global",
|
|
1259
|
-
"globalThis",
|
|
1260
|
-
"module",
|
|
1261
|
-
"exports",
|
|
1262
|
-
"__proto__"
|
|
1263
|
-
]);
|
|
1264
|
-
function sanitizeGlobalKey(key) {
|
|
1265
|
-
return key.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
1266
|
-
}
|
|
1267
|
-
function buildGlobals(context) {
|
|
1268
|
-
const globals = {};
|
|
1269
|
-
if (context.React) {
|
|
1270
|
-
globals["React"] = context.React;
|
|
1271
|
-
}
|
|
1272
|
-
if (context.ReactDOM) {
|
|
1273
|
-
globals["ReactDOM"] = context.ReactDOM;
|
|
1274
|
-
}
|
|
1275
|
-
if (context.React) {
|
|
1276
|
-
const jsxRuntime = createJSXRuntime(context.React);
|
|
1277
|
-
globals["__jsx"] = jsxRuntime["jsx"];
|
|
1278
|
-
globals["__jsxs"] = jsxRuntime["jsxs"];
|
|
1279
|
-
globals["__jsxDEV"] = jsxRuntime["jsxDEV"];
|
|
1280
|
-
globals["Fragment"] = jsxRuntime["Fragment"];
|
|
1281
|
-
}
|
|
1282
|
-
if (context.modules) {
|
|
1283
|
-
for (const [key, value] of Object.entries(context.modules)) {
|
|
1284
|
-
const sanitizedKey = sanitizeGlobalKey(key);
|
|
1285
|
-
if (DANGEROUS_GLOBAL_KEYS.has(sanitizedKey)) {
|
|
1286
|
-
throw new ExecutionError(
|
|
1287
|
-
`Dangerous module key '${key}' (sanitized: '${sanitizedKey}') is not allowed in execution context`,
|
|
1288
|
-
{ code: "SECURITY_VIOLATION" }
|
|
1289
|
-
);
|
|
1290
|
-
}
|
|
1291
|
-
globals[sanitizedKey] = value;
|
|
1292
|
-
}
|
|
1293
|
-
}
|
|
1294
|
-
if (context.globals) {
|
|
1295
|
-
for (const [key, value] of Object.entries(context.globals)) {
|
|
1296
|
-
if (DANGEROUS_GLOBAL_KEYS.has(key)) {
|
|
1297
|
-
throw new ExecutionError(`Dangerous global key '${key}' is not allowed in execution context`, {
|
|
1298
|
-
code: "SECURITY_VIOLATION"
|
|
1299
|
-
});
|
|
1300
|
-
}
|
|
1301
|
-
const sanitizedKey = sanitizeGlobalKey(key);
|
|
1302
|
-
if (DANGEROUS_GLOBAL_KEYS.has(sanitizedKey)) {
|
|
1303
|
-
throw new ExecutionError(
|
|
1304
|
-
`Dangerous global key '${key}' (sanitized: '${sanitizedKey}') is not allowed in execution context`,
|
|
1305
|
-
{ code: "SECURITY_VIOLATION" }
|
|
1306
|
-
);
|
|
1307
|
-
}
|
|
1308
|
-
globals[sanitizedKey] = value;
|
|
1309
|
-
}
|
|
1310
|
-
}
|
|
1311
|
-
return globals;
|
|
1312
|
-
}
|
|
1313
|
-
function buildRequireFunction(context) {
|
|
1314
|
-
const normalizedContextModules = {};
|
|
1315
|
-
if (context.modules) {
|
|
1316
|
-
for (const [key, value] of Object.entries(context.modules)) {
|
|
1317
|
-
normalizedContextModules[key.toLowerCase()] = value;
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
const modules = {
|
|
1321
|
-
react: context.React,
|
|
1322
|
-
"react-dom": context.ReactDOM,
|
|
1323
|
-
"react/jsx-runtime": context.React ? createJSXRuntime(context.React) : void 0,
|
|
1324
|
-
"react/jsx-dev-runtime": context.React ? createJSXRuntime(context.React) : void 0,
|
|
1325
|
-
...normalizedContextModules
|
|
1326
|
-
};
|
|
1327
|
-
return (id) => {
|
|
1328
|
-
const normalizedId = id.toLowerCase();
|
|
1329
|
-
if (normalizedId in modules) {
|
|
1330
|
-
const mod = modules[normalizedId];
|
|
1331
|
-
if (mod === void 0) {
|
|
1332
|
-
throw new Error(`Module '${id}' is not available. Did you forget to provide it in the context?`);
|
|
1333
|
-
}
|
|
1334
|
-
return mod;
|
|
1335
|
-
}
|
|
1336
|
-
throw new Error(`Module '${id}' is not available in the sandbox environment`);
|
|
1337
|
-
};
|
|
1338
|
-
}
|
|
1339
|
-
async function executeCode(code, context = {}) {
|
|
1340
|
-
const consoleOutput = [];
|
|
1341
|
-
const globals = buildGlobals(context);
|
|
1342
|
-
globals["console"] = {
|
|
1343
|
-
log: (...args) => {
|
|
1344
|
-
consoleOutput.push(args.map(String).join(" "));
|
|
1345
|
-
},
|
|
1346
|
-
info: (...args) => {
|
|
1347
|
-
consoleOutput.push(`[INFO] ${args.map(String).join(" ")}`);
|
|
1348
|
-
},
|
|
1349
|
-
warn: (...args) => {
|
|
1350
|
-
consoleOutput.push(`[WARN] ${args.map(String).join(" ")}`);
|
|
1351
|
-
},
|
|
1352
|
-
error: (...args) => {
|
|
1353
|
-
consoleOutput.push(`[ERROR] ${args.map(String).join(" ")}`);
|
|
1354
|
-
},
|
|
1355
|
-
debug: (...args) => {
|
|
1356
|
-
consoleOutput.push(`[DEBUG] ${args.map(String).join(" ")}`);
|
|
1357
|
-
},
|
|
1358
|
-
trace: () => {
|
|
1359
|
-
},
|
|
1360
|
-
dir: () => {
|
|
1361
|
-
},
|
|
1362
|
-
table: () => {
|
|
1363
|
-
},
|
|
1364
|
-
group: () => {
|
|
1365
|
-
},
|
|
1366
|
-
groupEnd: () => {
|
|
1367
|
-
},
|
|
1368
|
-
time: () => {
|
|
1369
|
-
},
|
|
1370
|
-
timeEnd: () => {
|
|
1371
|
-
},
|
|
1372
|
-
assert: () => {
|
|
1373
|
-
},
|
|
1374
|
-
clear: () => {
|
|
1375
|
-
},
|
|
1376
|
-
count: () => {
|
|
1377
|
-
},
|
|
1378
|
-
countReset: () => {
|
|
1379
|
-
}
|
|
1380
|
-
};
|
|
1381
|
-
globals["require"] = buildRequireFunction(context);
|
|
1382
|
-
const enclave = new import_enclave_vm.Enclave({
|
|
1383
|
-
...DEFAULT_ENCLAVE_OPTIONS,
|
|
1384
|
-
timeout: context.timeout ?? DEFAULT_ENCLAVE_OPTIONS.timeout,
|
|
1385
|
-
maxIterations: context.maxIterations ?? DEFAULT_ENCLAVE_OPTIONS.maxIterations,
|
|
1386
|
-
securityLevel: mapSecurityLevel(context.security),
|
|
1387
|
-
globals,
|
|
1388
|
-
allowFunctionsInGlobals: true
|
|
1389
|
-
// Required for React components
|
|
1390
|
-
});
|
|
1391
|
-
try {
|
|
1392
|
-
const wrappedCode = `
|
|
1393
|
-
const module = { exports: {} };
|
|
1394
|
-
const exports = module.exports;
|
|
1395
|
-
const __filename = 'widget.js';
|
|
1396
|
-
const __dirname = '/';
|
|
1397
|
-
${code}
|
|
1398
|
-
return module.exports;
|
|
1399
|
-
`;
|
|
1400
|
-
const result = await enclave.run(wrappedCode);
|
|
1401
|
-
if (!result.success) {
|
|
1402
|
-
const errorMessage = result.error?.message ?? "Execution failed";
|
|
1403
|
-
const errorCode = result.error?.code;
|
|
1404
|
-
if (errorCode === "TIMEOUT") {
|
|
1405
|
-
throw new ExecutionError(`Execution timed out after ${context.timeout ?? DEFAULT_ENCLAVE_OPTIONS.timeout}ms`, {
|
|
1406
|
-
code: "TIMEOUT"
|
|
1407
|
-
});
|
|
1408
|
-
}
|
|
1409
|
-
if (errorCode === "MAX_ITERATIONS") {
|
|
1410
|
-
throw new ExecutionError(
|
|
1411
|
-
`Maximum iterations exceeded (${context.maxIterations ?? DEFAULT_ENCLAVE_OPTIONS.maxIterations})`,
|
|
1412
|
-
{
|
|
1413
|
-
code: "MAX_ITERATIONS"
|
|
1414
|
-
}
|
|
1415
|
-
);
|
|
1416
|
-
}
|
|
1417
|
-
if (errorCode === "VALIDATION_ERROR") {
|
|
1418
|
-
throw new ExecutionError(`Security validation failed: ${errorMessage}`, { code: "SECURITY_VIOLATION" });
|
|
1419
|
-
}
|
|
1420
|
-
throw new ExecutionError(errorMessage, result.error);
|
|
1421
|
-
}
|
|
1422
|
-
return {
|
|
1423
|
-
exports: result.value,
|
|
1424
|
-
executionTime: result.stats.duration,
|
|
1425
|
-
consoleOutput: consoleOutput.length > 0 ? consoleOutput : void 0
|
|
1426
|
-
};
|
|
1427
|
-
} finally {
|
|
1428
|
-
enclave.dispose();
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
async function executeDefault(code, context = {}) {
|
|
1432
|
-
const result = await executeCode(code, context);
|
|
1433
|
-
if ("default" in result.exports) {
|
|
1434
|
-
return result.exports.default;
|
|
1435
|
-
}
|
|
1436
|
-
const exportKeys = Object.keys(result.exports);
|
|
1437
|
-
if (exportKeys.length === 0) {
|
|
1438
|
-
throw new ExecutionError("Code did not export any values");
|
|
1439
|
-
}
|
|
1440
|
-
if (exportKeys.length === 1) {
|
|
1441
|
-
return result.exports[exportKeys[0]];
|
|
1442
|
-
}
|
|
1443
|
-
return result.exports;
|
|
1444
|
-
}
|
|
1445
|
-
var ExecutionError = class extends Error {
|
|
1446
|
-
/** Error code for categorization */
|
|
1447
|
-
code;
|
|
1448
|
-
constructor(message, cause) {
|
|
1449
|
-
super(message, { cause });
|
|
1450
|
-
this.name = "ExecutionError";
|
|
1451
|
-
if (cause && typeof cause === "object" && "code" in cause) {
|
|
1452
|
-
this.code = cause.code;
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
};
|
|
1456
|
-
function isExecutionError(error) {
|
|
1457
|
-
return error instanceof ExecutionError;
|
|
1458
|
-
}
|
|
1459
|
-
|
|
1460
|
-
// libs/ui/src/utils/escape-html.ts
|
|
1461
|
-
function escapeHtml(str) {
|
|
1462
|
-
if (str === null || str === void 0) {
|
|
1463
|
-
return "";
|
|
1464
|
-
}
|
|
1465
|
-
const s = String(str);
|
|
1466
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
1467
|
-
}
|
|
1468
|
-
function escapeHtmlAttr(str) {
|
|
1469
|
-
return str.replace(/&/g, "&").replace(/"/g, """);
|
|
1470
|
-
}
|
|
1471
|
-
|
|
1472
|
-
// libs/ui/src/universal/types.ts
|
|
1473
|
-
var UNIVERSAL_CDN = {
|
|
1474
|
-
esm: {
|
|
1475
|
-
reactMarkdown: "https://esm.sh/react-markdown@9",
|
|
1476
|
-
mdxReact: "https://esm.sh/@mdx-js/react@3",
|
|
1477
|
-
remarkGfm: "https://esm.sh/remark-gfm@4"
|
|
1478
|
-
}
|
|
1479
|
-
// Note: These libraries are not available on cdnjs
|
|
1480
|
-
// For Claude, we use inline implementations
|
|
1481
|
-
};
|
|
1482
|
-
function detectContentType(source) {
|
|
1483
|
-
if (typeof source === "function") {
|
|
1484
|
-
return "react";
|
|
1485
|
-
}
|
|
1486
|
-
if (typeof source !== "string") {
|
|
1487
|
-
return "html";
|
|
1488
|
-
}
|
|
1489
|
-
const hasModuleSyntax = /^import\s+/m.test(source) || /^export\s+(default\s+)?/m.test(source) || /^const\s+\w+\s*=\s*\([^)]*\)\s*=>/m.test(source) || // Arrow function components
|
|
1490
|
-
/^function\s+\w+\s*\(/m.test(source);
|
|
1491
|
-
const hasJsxTags = /<[A-Z][a-zA-Z]*/.test(source);
|
|
1492
|
-
const hasMarkdown = /^#{1,6}\s/m.test(source) || /^\*\s/m.test(source) || /^-\s/m.test(source) || /^\d+\.\s/m.test(source);
|
|
1493
|
-
if (hasModuleSyntax && hasJsxTags) {
|
|
1494
|
-
return "react";
|
|
1495
|
-
}
|
|
1496
|
-
if (hasJsxTags && hasMarkdown && !hasModuleSyntax) {
|
|
1497
|
-
return "mdx";
|
|
1498
|
-
}
|
|
1499
|
-
if (hasMarkdown || /\*\*[^*]+\*\*/.test(source) || /\[[^\]]+\]\([^)]+\)/.test(source)) {
|
|
1500
|
-
return "markdown";
|
|
1501
|
-
}
|
|
1502
|
-
if (hasJsxTags && !hasModuleSyntax) {
|
|
1503
|
-
return "mdx";
|
|
1504
|
-
}
|
|
1505
|
-
return "html";
|
|
1506
|
-
}
|
|
1507
|
-
|
|
1508
|
-
// libs/ui/src/universal/cached-runtime.ts
|
|
1509
|
-
var RUNTIME_PLACEHOLDERS = {
|
|
1510
|
-
/** Placeholder for transpiled component code */
|
|
1511
|
-
COMPONENT_CODE: "/*__FRONTMCP_COMPONENT_CODE__*/",
|
|
1512
|
-
/** Placeholder for data injection */
|
|
1513
|
-
DATA_INJECTION: "/*__FRONTMCP_DATA_INJECTION__*/",
|
|
1514
|
-
/** Placeholder for custom components */
|
|
1515
|
-
CUSTOM_COMPONENTS: "/*__FRONTMCP_CUSTOM_COMPONENTS__*/"
|
|
290
|
+
// libs/ui/src/universal/cached-runtime.ts
|
|
291
|
+
var import_runtime = require("@frontmcp/uipack/runtime");
|
|
292
|
+
var import_build = require("@frontmcp/uipack/build");
|
|
293
|
+
var RUNTIME_PLACEHOLDERS = {
|
|
294
|
+
/** Placeholder for transpiled component code */
|
|
295
|
+
COMPONENT_CODE: "/*__FRONTMCP_COMPONENT_CODE__*/",
|
|
296
|
+
/** Placeholder for data injection */
|
|
297
|
+
DATA_INJECTION: "/*__FRONTMCP_DATA_INJECTION__*/",
|
|
298
|
+
/** Placeholder for custom components */
|
|
299
|
+
CUSTOM_COMPONENTS: "/*__FRONTMCP_CUSTOM_COMPONENTS__*/"
|
|
1516
300
|
};
|
|
1517
301
|
var runtimeCache = /* @__PURE__ */ new Map();
|
|
1518
302
|
var DEFAULT_CACHE_CONFIG = {
|
|
@@ -1531,6 +315,7 @@ function generateCacheKey(options) {
|
|
|
1531
315
|
options.includeMarkdown ? "md" : "",
|
|
1532
316
|
options.includeMdx ? "mdx" : "",
|
|
1533
317
|
options.minify ? "min" : "",
|
|
318
|
+
options.includeBridge ? "bridge" : "",
|
|
1534
319
|
securityKey
|
|
1535
320
|
].filter(Boolean).join(":");
|
|
1536
321
|
}
|
|
@@ -1574,6 +359,17 @@ function buildStoreRuntime() {
|
|
|
1574
359
|
context: state,
|
|
1575
360
|
setContext: function(ctx) {
|
|
1576
361
|
this.setState(ctx);
|
|
362
|
+
},
|
|
363
|
+
// Dynamic mode: update output and re-render
|
|
364
|
+
updateOutput: function(output) {
|
|
365
|
+
this.setState({ output: output, loading: false });
|
|
366
|
+
// Also update the global window variable for compatibility
|
|
367
|
+
window.__mcpToolOutput = output;
|
|
368
|
+
},
|
|
369
|
+
// Dynamic mode: update input and re-render
|
|
370
|
+
updateInput: function(input) {
|
|
371
|
+
this.setState({ input: input });
|
|
372
|
+
window.__mcpToolInput = input;
|
|
1577
373
|
}
|
|
1578
374
|
};
|
|
1579
375
|
|
|
@@ -1598,6 +394,32 @@ function buildStoreRuntime() {
|
|
|
1598
394
|
window.useContent = function() {
|
|
1599
395
|
return window.useFrontMCPStore().content;
|
|
1600
396
|
};
|
|
397
|
+
|
|
398
|
+
// Connect to MCP Bridge for platform data detection
|
|
399
|
+
function initFromBridge() {
|
|
400
|
+
// Check for data from mcpBridge (handles OpenAI, ext-apps, etc.)
|
|
401
|
+
if (window.mcpBridge && window.mcpBridge.toolOutput != null) {
|
|
402
|
+
window.__frontmcp.setState({
|
|
403
|
+
output: window.mcpBridge.toolOutput,
|
|
404
|
+
loading: false
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Subscribe to bridge updates via onToolResult
|
|
409
|
+
if (window.mcpBridge && window.mcpBridge.onToolResult) {
|
|
410
|
+
window.mcpBridge.onToolResult(function(result) {
|
|
411
|
+
window.__frontmcp.updateOutput(result);
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Initialize from bridge when ready
|
|
417
|
+
if (window.mcpBridge) {
|
|
418
|
+
initFromBridge();
|
|
419
|
+
} else {
|
|
420
|
+
// Wait for bridge to be ready
|
|
421
|
+
window.addEventListener('mcp:bridge-ready', initFromBridge);
|
|
422
|
+
}
|
|
1601
423
|
})();
|
|
1602
424
|
`;
|
|
1603
425
|
}
|
|
@@ -1817,71 +639,7 @@ function buildRenderersRuntime(options) {
|
|
|
1817
639
|
`;
|
|
1818
640
|
}
|
|
1819
641
|
function buildUIComponentsRuntime() {
|
|
1820
|
-
return
|
|
1821
|
-
// UI Components (Vendor)
|
|
1822
|
-
(function() {
|
|
1823
|
-
window.Card = function(props) {
|
|
1824
|
-
var children = props.children;
|
|
1825
|
-
var title = props.title;
|
|
1826
|
-
var className = props.className || '';
|
|
1827
|
-
return React.createElement('div', {
|
|
1828
|
-
className: 'bg-white rounded-lg shadow border border-gray-200 overflow-hidden ' + className
|
|
1829
|
-
}, [
|
|
1830
|
-
title && React.createElement('div', {
|
|
1831
|
-
key: 'header',
|
|
1832
|
-
className: 'px-4 py-3 border-b border-gray-200 bg-gray-50'
|
|
1833
|
-
}, React.createElement('h3', { className: 'text-sm font-medium text-gray-900' }, title)),
|
|
1834
|
-
React.createElement('div', { key: 'body', className: 'p-4' }, children)
|
|
1835
|
-
]);
|
|
1836
|
-
};
|
|
1837
|
-
|
|
1838
|
-
window.Badge = function(props) {
|
|
1839
|
-
var children = props.children;
|
|
1840
|
-
var variant = props.variant || 'default';
|
|
1841
|
-
var variantClasses = {
|
|
1842
|
-
default: 'bg-gray-100 text-gray-800',
|
|
1843
|
-
success: 'bg-green-100 text-green-800',
|
|
1844
|
-
warning: 'bg-yellow-100 text-yellow-800',
|
|
1845
|
-
error: 'bg-red-100 text-red-800',
|
|
1846
|
-
info: 'bg-blue-100 text-blue-800'
|
|
1847
|
-
};
|
|
1848
|
-
return React.createElement('span', {
|
|
1849
|
-
className: 'inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ' + (variantClasses[variant] || variantClasses.default)
|
|
1850
|
-
}, children);
|
|
1851
|
-
};
|
|
1852
|
-
|
|
1853
|
-
window.Button = function(props) {
|
|
1854
|
-
var children = props.children;
|
|
1855
|
-
var variant = props.variant || 'primary';
|
|
1856
|
-
var onClick = props.onClick;
|
|
1857
|
-
var disabled = props.disabled;
|
|
1858
|
-
var variantClasses = {
|
|
1859
|
-
primary: 'bg-blue-600 text-white hover:bg-blue-700',
|
|
1860
|
-
secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
|
|
1861
|
-
outline: 'border border-gray-300 text-gray-700 hover:bg-gray-50',
|
|
1862
|
-
danger: 'bg-red-600 text-white hover:bg-red-700'
|
|
1863
|
-
};
|
|
1864
|
-
return React.createElement('button', {
|
|
1865
|
-
className: 'px-4 py-2 rounded-md text-sm font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 ' +
|
|
1866
|
-
(disabled ? 'opacity-50 cursor-not-allowed ' : '') +
|
|
1867
|
-
(variantClasses[variant] || variantClasses.primary),
|
|
1868
|
-
onClick: onClick,
|
|
1869
|
-
disabled: disabled
|
|
1870
|
-
}, children);
|
|
1871
|
-
};
|
|
1872
|
-
|
|
1873
|
-
// Export to namespace
|
|
1874
|
-
window.frontmcp_ui_namespaceObject = Object.assign({}, window.React || {}, {
|
|
1875
|
-
useToolOutput: window.useToolOutput,
|
|
1876
|
-
useToolInput: window.useToolInput,
|
|
1877
|
-
useMcpBridgeContext: function() { return window.__frontmcp.context; },
|
|
1878
|
-
useCallTool: function() { return function() { return Promise.resolve(null); }; },
|
|
1879
|
-
Card: window.Card,
|
|
1880
|
-
Badge: window.Badge,
|
|
1881
|
-
Button: window.Button
|
|
1882
|
-
});
|
|
1883
|
-
})();
|
|
1884
|
-
`;
|
|
642
|
+
return (0, import_build.buildUIComponentsRuntime)();
|
|
1885
643
|
}
|
|
1886
644
|
function buildUniversalAppRuntime() {
|
|
1887
645
|
return `
|
|
@@ -2006,7 +764,11 @@ function getCachedRuntime(options, config = {}) {
|
|
|
2006
764
|
}
|
|
2007
765
|
runtimeCache.delete(cacheKey);
|
|
2008
766
|
}
|
|
2009
|
-
const vendorParts = [
|
|
767
|
+
const vendorParts = [];
|
|
768
|
+
if (options.includeBridge) {
|
|
769
|
+
vendorParts.push((0, import_runtime.getMCPBridgeScript)());
|
|
770
|
+
}
|
|
771
|
+
vendorParts.push(buildStoreRuntime(), buildRequireShim());
|
|
2010
772
|
if (options.cdnType === "umd" || options.includeMarkdown) {
|
|
2011
773
|
vendorParts.push(buildInlineMarkdownParser(options));
|
|
2012
774
|
}
|
|
@@ -2045,12 +807,51 @@ function buildAppTemplate() {
|
|
|
2045
807
|
return [buildCustomComponentsWrapper(), buildComponentWrapper(), buildDataInjectionWrapper()].join("\n");
|
|
2046
808
|
}
|
|
2047
809
|
function minifyScript(script) {
|
|
2048
|
-
return script.replace(
|
|
810
|
+
return script.replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/[^\n]*$/gm, "").replace(/\n\s*\n/g, "\n").replace(/^\s+/gm, "").trim();
|
|
2049
811
|
}
|
|
2050
812
|
function buildAppScript(appTemplate, componentCode, dataInjection, customComponents = "") {
|
|
2051
813
|
return appTemplate.replace(RUNTIME_PLACEHOLDERS.CUSTOM_COMPONENTS, customComponents || "// No custom components").replace(RUNTIME_PLACEHOLDERS.COMPONENT_CODE, componentCode || "// No component code").replace(RUNTIME_PLACEHOLDERS.DATA_INJECTION, dataInjection);
|
|
2052
814
|
}
|
|
2053
|
-
|
|
815
|
+
var DEFAULT_OUTPUT_PLACEHOLDER = "__FRONTMCP_OUTPUT_PLACEHOLDER__";
|
|
816
|
+
var DEFAULT_INPUT_PLACEHOLDER = "__FRONTMCP_INPUT_PLACEHOLDER__";
|
|
817
|
+
function buildDataInjectionCode(toolName, input, output, structuredContent, contentType, source, hasComponent, options) {
|
|
818
|
+
const buildMode = options?.buildMode ?? "static";
|
|
819
|
+
const cdnType = options?.cdnType ?? "esm";
|
|
820
|
+
switch (buildMode) {
|
|
821
|
+
case "dynamic":
|
|
822
|
+
return buildDynamicDataInjectionCode(
|
|
823
|
+
toolName,
|
|
824
|
+
input,
|
|
825
|
+
output,
|
|
826
|
+
structuredContent,
|
|
827
|
+
contentType,
|
|
828
|
+
source,
|
|
829
|
+
hasComponent,
|
|
830
|
+
cdnType,
|
|
831
|
+
options?.dynamicOptions
|
|
832
|
+
);
|
|
833
|
+
case "hybrid":
|
|
834
|
+
return buildHybridDataInjectionCode(
|
|
835
|
+
toolName,
|
|
836
|
+
structuredContent,
|
|
837
|
+
contentType,
|
|
838
|
+
source,
|
|
839
|
+
hasComponent,
|
|
840
|
+
options?.hybridOptions
|
|
841
|
+
);
|
|
842
|
+
default:
|
|
843
|
+
return buildStaticDataInjectionCode(
|
|
844
|
+
toolName,
|
|
845
|
+
input,
|
|
846
|
+
output,
|
|
847
|
+
structuredContent,
|
|
848
|
+
contentType,
|
|
849
|
+
source,
|
|
850
|
+
hasComponent
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
function buildStaticDataInjectionCode(toolName, input, output, structuredContent, contentType, source, hasComponent) {
|
|
2054
855
|
const safeJson = (value) => {
|
|
2055
856
|
try {
|
|
2056
857
|
return JSON.stringify(value);
|
|
@@ -2060,6 +861,7 @@ function buildDataInjectionCode(toolName, input, output, structuredContent, cont
|
|
|
2060
861
|
};
|
|
2061
862
|
if (hasComponent) {
|
|
2062
863
|
return `
|
|
864
|
+
// Static Mode - Data baked at build time
|
|
2063
865
|
window.__frontmcp.setState({
|
|
2064
866
|
toolName: ${safeJson(toolName)},
|
|
2065
867
|
input: ${safeJson(input ?? null)},
|
|
@@ -2074,6 +876,7 @@ function buildDataInjectionCode(toolName, input, output, structuredContent, cont
|
|
|
2074
876
|
});`;
|
|
2075
877
|
}
|
|
2076
878
|
return `
|
|
879
|
+
// Static Mode - Data baked at build time
|
|
2077
880
|
window.__frontmcp.setState({
|
|
2078
881
|
toolName: ${safeJson(toolName)},
|
|
2079
882
|
input: ${safeJson(input ?? null)},
|
|
@@ -2087,6 +890,181 @@ function buildDataInjectionCode(toolName, input, output, structuredContent, cont
|
|
|
2087
890
|
error: null
|
|
2088
891
|
});`;
|
|
2089
892
|
}
|
|
893
|
+
function buildDynamicDataInjectionCode(toolName, input, output, structuredContent, contentType, source, hasComponent, cdnType, dynamicOptions) {
|
|
894
|
+
if (cdnType === "umd") {
|
|
895
|
+
return buildDynamicWithPlaceholdersCode(
|
|
896
|
+
toolName,
|
|
897
|
+
structuredContent,
|
|
898
|
+
contentType,
|
|
899
|
+
source,
|
|
900
|
+
hasComponent,
|
|
901
|
+
dynamicOptions
|
|
902
|
+
);
|
|
903
|
+
}
|
|
904
|
+
return buildDynamicWithSubscriptionCode(
|
|
905
|
+
toolName,
|
|
906
|
+
input,
|
|
907
|
+
output,
|
|
908
|
+
structuredContent,
|
|
909
|
+
contentType,
|
|
910
|
+
source,
|
|
911
|
+
hasComponent,
|
|
912
|
+
dynamicOptions
|
|
913
|
+
);
|
|
914
|
+
}
|
|
915
|
+
function buildDynamicWithPlaceholdersCode(toolName, structuredContent, contentType, source, hasComponent, dynamicOptions) {
|
|
916
|
+
const safeJson = (value) => {
|
|
917
|
+
try {
|
|
918
|
+
return JSON.stringify(value);
|
|
919
|
+
} catch {
|
|
920
|
+
return "null";
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
const outputPlaceholder = DEFAULT_OUTPUT_PLACEHOLDER;
|
|
924
|
+
const inputPlaceholder = DEFAULT_INPUT_PLACEHOLDER;
|
|
925
|
+
const includeInitialData = dynamicOptions?.includeInitialData ?? true;
|
|
926
|
+
const contentBlock = hasComponent ? `content: { type: 'react', source: window.__frontmcp_component }` : `content: { type: ${safeJson(contentType)}, source: ${safeJson(source)} }`;
|
|
927
|
+
return `
|
|
928
|
+
// Dynamic Mode - Placeholder-based for non-OpenAI platforms
|
|
929
|
+
var __outputRaw = "${outputPlaceholder}";
|
|
930
|
+
var __inputRaw = "${inputPlaceholder}";
|
|
931
|
+
var __output = null;
|
|
932
|
+
var __input = null;
|
|
933
|
+
var __error = null;
|
|
934
|
+
var __outputNotReplaced = false;
|
|
935
|
+
var __includeInitialData = ${includeInitialData};
|
|
936
|
+
|
|
937
|
+
// Parse output placeholder
|
|
938
|
+
if (typeof __outputRaw === 'string' && __outputRaw !== "${outputPlaceholder}") {
|
|
939
|
+
try { __output = JSON.parse(__outputRaw); } catch (e) {
|
|
940
|
+
console.warn('[FrontMCP] Failed to parse output:', e);
|
|
941
|
+
__error = 'Failed to parse output data';
|
|
942
|
+
}
|
|
943
|
+
} else if (__outputRaw === "${outputPlaceholder}") {
|
|
944
|
+
__outputNotReplaced = true;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
// Parse input placeholder
|
|
948
|
+
if (typeof __inputRaw === 'string' && __inputRaw !== "${inputPlaceholder}") {
|
|
949
|
+
try { __input = JSON.parse(__inputRaw); } catch (e) { console.warn('[FrontMCP] Failed to parse input:', e); }
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
// Handle placeholder not replaced - show error if expecting initial data
|
|
953
|
+
if (__outputNotReplaced && __includeInitialData) {
|
|
954
|
+
__error = 'No data provided. The output placeholder was not replaced.';
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
window.__frontmcp.setState({
|
|
958
|
+
toolName: ${safeJson(toolName)},
|
|
959
|
+
input: __input,
|
|
960
|
+
output: __output,
|
|
961
|
+
structuredContent: ${safeJson(structuredContent ?? null)},
|
|
962
|
+
${contentBlock},
|
|
963
|
+
loading: !__includeInitialData && __output === null && !__error,
|
|
964
|
+
error: __error
|
|
965
|
+
});`;
|
|
966
|
+
}
|
|
967
|
+
function buildDynamicWithSubscriptionCode(toolName, input, output, structuredContent, contentType, source, hasComponent, dynamicOptions) {
|
|
968
|
+
const safeJson = (value) => {
|
|
969
|
+
try {
|
|
970
|
+
return JSON.stringify(value);
|
|
971
|
+
} catch {
|
|
972
|
+
return "null";
|
|
973
|
+
}
|
|
974
|
+
};
|
|
975
|
+
const includeInitialData = dynamicOptions?.includeInitialData ?? true;
|
|
976
|
+
const subscribeToUpdates = dynamicOptions?.subscribeToUpdates ?? true;
|
|
977
|
+
const contentBlock = hasComponent ? `content: { type: 'react', source: window.__frontmcp_component }` : `content: { type: ${safeJson(contentType)}, source: ${safeJson(source)} }`;
|
|
978
|
+
const initialState = includeInitialData ? `{
|
|
979
|
+
toolName: ${safeJson(toolName)},
|
|
980
|
+
input: ${safeJson(input ?? null)},
|
|
981
|
+
output: ${safeJson(output ?? null)},
|
|
982
|
+
structuredContent: ${safeJson(structuredContent ?? null)},
|
|
983
|
+
${contentBlock},
|
|
984
|
+
loading: false,
|
|
985
|
+
error: null
|
|
986
|
+
}` : `{
|
|
987
|
+
toolName: ${safeJson(toolName)},
|
|
988
|
+
input: ${safeJson(input ?? null)},
|
|
989
|
+
output: null,
|
|
990
|
+
structuredContent: ${safeJson(structuredContent ?? null)},
|
|
991
|
+
${contentBlock},
|
|
992
|
+
loading: true,
|
|
993
|
+
error: null
|
|
994
|
+
}`;
|
|
995
|
+
const subscriptionBlock = subscribeToUpdates ? `
|
|
996
|
+
// Subscribe to platform tool result events
|
|
997
|
+
(function() {
|
|
998
|
+
function subscribeToUpdates() {
|
|
999
|
+
if (window.openai && window.openai.canvas && window.openai.canvas.onToolResult) {
|
|
1000
|
+
window.openai.canvas.onToolResult(function(result) {
|
|
1001
|
+
window.__frontmcp.updateOutput(result);
|
|
1002
|
+
window.dispatchEvent(new CustomEvent('frontmcp:toolResult', { detail: result }));
|
|
1003
|
+
});
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
if (document.readyState === 'loading') {
|
|
1007
|
+
document.addEventListener('DOMContentLoaded', subscribeToUpdates);
|
|
1008
|
+
} else {
|
|
1009
|
+
subscribeToUpdates();
|
|
1010
|
+
}
|
|
1011
|
+
})();` : "";
|
|
1012
|
+
return `
|
|
1013
|
+
// Dynamic Mode - OpenAI Subscription
|
|
1014
|
+
window.__frontmcp.setState(${initialState});
|
|
1015
|
+
${subscriptionBlock}`;
|
|
1016
|
+
}
|
|
1017
|
+
function buildHybridDataInjectionCode(toolName, structuredContent, contentType, source, hasComponent, hybridOptions) {
|
|
1018
|
+
const safeJson = (value) => {
|
|
1019
|
+
try {
|
|
1020
|
+
return JSON.stringify(value);
|
|
1021
|
+
} catch {
|
|
1022
|
+
return "null";
|
|
1023
|
+
}
|
|
1024
|
+
};
|
|
1025
|
+
const outputPlaceholder = hybridOptions?.placeholder ?? DEFAULT_OUTPUT_PLACEHOLDER;
|
|
1026
|
+
const inputPlaceholder = hybridOptions?.inputPlaceholder ?? DEFAULT_INPUT_PLACEHOLDER;
|
|
1027
|
+
const contentBlock = hasComponent ? `content: { type: 'react', source: window.__frontmcp_component }` : `content: { type: ${safeJson(contentType)}, source: ${safeJson(source)} }`;
|
|
1028
|
+
return `
|
|
1029
|
+
// Hybrid Mode - Placeholders replaced at runtime
|
|
1030
|
+
var __outputRaw = "${outputPlaceholder}";
|
|
1031
|
+
var __inputRaw = "${inputPlaceholder}";
|
|
1032
|
+
var __output = null;
|
|
1033
|
+
var __input = null;
|
|
1034
|
+
var __error = null;
|
|
1035
|
+
var __outputNotReplaced = false;
|
|
1036
|
+
|
|
1037
|
+
// Parse output placeholder
|
|
1038
|
+
if (typeof __outputRaw === 'string' && __outputRaw !== "${outputPlaceholder}") {
|
|
1039
|
+
try { __output = JSON.parse(__outputRaw); } catch (e) {
|
|
1040
|
+
console.warn('[FrontMCP] Failed to parse output:', e);
|
|
1041
|
+
__error = 'Failed to parse output data';
|
|
1042
|
+
}
|
|
1043
|
+
} else if (__outputRaw === "${outputPlaceholder}") {
|
|
1044
|
+
// Placeholder not replaced - no data was injected
|
|
1045
|
+
__outputNotReplaced = true;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
// Parse input placeholder
|
|
1049
|
+
if (typeof __inputRaw === 'string' && __inputRaw !== "${inputPlaceholder}") {
|
|
1050
|
+
try { __input = JSON.parse(__inputRaw); } catch (e) { console.warn('[FrontMCP] Failed to parse input:', e); }
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
// Set error if output placeholder was not replaced (no data provided)
|
|
1054
|
+
if (__outputNotReplaced) {
|
|
1055
|
+
__error = 'No data provided. The output placeholder was not replaced.';
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
window.__frontmcp.setState({
|
|
1059
|
+
toolName: ${safeJson(toolName)},
|
|
1060
|
+
input: __input,
|
|
1061
|
+
output: __output,
|
|
1062
|
+
structuredContent: ${safeJson(structuredContent ?? null)},
|
|
1063
|
+
${contentBlock},
|
|
1064
|
+
loading: false,
|
|
1065
|
+
error: __error
|
|
1066
|
+
});`;
|
|
1067
|
+
}
|
|
2090
1068
|
function buildComponentCode(transpiledCode) {
|
|
2091
1069
|
return `
|
|
2092
1070
|
// CommonJS module shim
|
|
@@ -2101,24 +1079,395 @@ function buildComponentCode(transpiledCode) {
|
|
|
2101
1079
|
}
|
|
2102
1080
|
|
|
2103
1081
|
// libs/ui/src/bundler/bundler.ts
|
|
2104
|
-
var
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
1082
|
+
var import_build2 = require("@frontmcp/uipack/build");
|
|
1083
|
+
|
|
1084
|
+
// libs/ui/src/bundler/browser-components.ts
|
|
1085
|
+
var path = __toESM(require("path"));
|
|
1086
|
+
var cachedBrowserComponents = null;
|
|
1087
|
+
var buildingPromise = null;
|
|
1088
|
+
function getComponentsEntrySource() {
|
|
1089
|
+
return `
|
|
1090
|
+
// Browser Components Entry Point
|
|
1091
|
+
// This gets transpiled by esbuild to create browser-compatible code
|
|
1092
|
+
|
|
1093
|
+
import {
|
|
1094
|
+
// Card styles
|
|
1095
|
+
CARD_VARIANTS,
|
|
1096
|
+
CARD_SIZES,
|
|
1097
|
+
// Button styles
|
|
1098
|
+
BUTTON_VARIANTS,
|
|
1099
|
+
BUTTON_SIZES,
|
|
1100
|
+
BUTTON_ICON_SIZES,
|
|
1101
|
+
BUTTON_BASE_CLASSES,
|
|
1102
|
+
LOADING_SPINNER,
|
|
1103
|
+
// Badge styles
|
|
1104
|
+
BADGE_VARIANTS,
|
|
1105
|
+
BADGE_SIZES,
|
|
1106
|
+
BADGE_DOT_SIZES,
|
|
1107
|
+
BADGE_DOT_VARIANTS,
|
|
1108
|
+
// Alert styles
|
|
1109
|
+
ALERT_VARIANTS,
|
|
1110
|
+
ALERT_BASE_CLASSES,
|
|
1111
|
+
ALERT_ICONS,
|
|
1112
|
+
CLOSE_ICON,
|
|
1113
|
+
// Utility
|
|
1114
|
+
cn,
|
|
1115
|
+
} from '@frontmcp/uipack/styles';
|
|
1116
|
+
|
|
1117
|
+
// Re-export for the IIFE
|
|
1118
|
+
export {
|
|
1119
|
+
CARD_VARIANTS,
|
|
1120
|
+
CARD_SIZES,
|
|
1121
|
+
BUTTON_VARIANTS,
|
|
1122
|
+
BUTTON_SIZES,
|
|
1123
|
+
BUTTON_ICON_SIZES,
|
|
1124
|
+
BUTTON_BASE_CLASSES,
|
|
1125
|
+
LOADING_SPINNER,
|
|
1126
|
+
BADGE_VARIANTS,
|
|
1127
|
+
BADGE_SIZES,
|
|
1128
|
+
BADGE_DOT_SIZES,
|
|
1129
|
+
BADGE_DOT_VARIANTS,
|
|
1130
|
+
ALERT_VARIANTS,
|
|
1131
|
+
ALERT_BASE_CLASSES,
|
|
1132
|
+
ALERT_ICONS,
|
|
1133
|
+
CLOSE_ICON,
|
|
1134
|
+
cn,
|
|
1135
|
+
};
|
|
1136
|
+
|
|
1137
|
+
// Card Component
|
|
1138
|
+
export function Card(props: any) {
|
|
1139
|
+
const {
|
|
1140
|
+
title,
|
|
1141
|
+
subtitle,
|
|
1142
|
+
headerActions,
|
|
1143
|
+
footer,
|
|
1144
|
+
variant = 'default',
|
|
1145
|
+
size = 'md',
|
|
1146
|
+
className,
|
|
1147
|
+
id,
|
|
1148
|
+
clickable,
|
|
1149
|
+
href,
|
|
1150
|
+
children,
|
|
1151
|
+
} = props;
|
|
1152
|
+
|
|
1153
|
+
const variantClasses = CARD_VARIANTS[variant] || CARD_VARIANTS.default;
|
|
1154
|
+
const sizeClasses = CARD_SIZES[size] || CARD_SIZES.md;
|
|
1155
|
+
const clickableClasses = clickable ? 'cursor-pointer hover:shadow-md transition-shadow' : '';
|
|
1156
|
+
const allClasses = cn(variantClasses, sizeClasses, clickableClasses, className);
|
|
1157
|
+
|
|
1158
|
+
const hasHeader = title || subtitle || headerActions;
|
|
1159
|
+
|
|
1160
|
+
const headerElement = hasHeader ? React.createElement('div', {
|
|
1161
|
+
className: 'flex items-start justify-between mb-4'
|
|
1162
|
+
}, [
|
|
1163
|
+
React.createElement('div', { key: 'titles' }, [
|
|
1164
|
+
title && React.createElement('h3', {
|
|
1165
|
+
key: 'title',
|
|
1166
|
+
className: 'text-lg font-semibold text-text-primary'
|
|
1167
|
+
}, title),
|
|
1168
|
+
subtitle && React.createElement('p', {
|
|
1169
|
+
key: 'subtitle',
|
|
1170
|
+
className: 'text-sm text-text-secondary mt-1'
|
|
1171
|
+
}, subtitle)
|
|
1172
|
+
]),
|
|
1173
|
+
headerActions && React.createElement('div', {
|
|
1174
|
+
key: 'actions',
|
|
1175
|
+
className: 'flex items-center gap-2'
|
|
1176
|
+
}, headerActions)
|
|
1177
|
+
]) : null;
|
|
1178
|
+
|
|
1179
|
+
const footerElement = footer ? React.createElement('div', {
|
|
1180
|
+
className: 'mt-4 pt-4 border-t border-divider'
|
|
1181
|
+
}, footer) : null;
|
|
1182
|
+
|
|
1183
|
+
const content = React.createElement(React.Fragment, null, headerElement, children, footerElement);
|
|
1184
|
+
|
|
1185
|
+
if (href) {
|
|
1186
|
+
return React.createElement('a', { href, className: allClasses, id }, content);
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
return React.createElement('div', { className: allClasses, id }, content);
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
// Button Component
|
|
1193
|
+
export function Button(props: any) {
|
|
1194
|
+
const {
|
|
1195
|
+
variant = 'primary',
|
|
1196
|
+
size = 'md',
|
|
1197
|
+
disabled = false,
|
|
1198
|
+
loading = false,
|
|
1199
|
+
fullWidth = false,
|
|
1200
|
+
iconPosition = 'left',
|
|
1201
|
+
icon,
|
|
1202
|
+
iconOnly = false,
|
|
1203
|
+
type = 'button',
|
|
1204
|
+
className,
|
|
1205
|
+
onClick,
|
|
1206
|
+
children,
|
|
1207
|
+
} = props;
|
|
1208
|
+
|
|
1209
|
+
const variantClasses = BUTTON_VARIANTS[variant] || BUTTON_VARIANTS.primary;
|
|
1210
|
+
const sizeClasses = iconOnly
|
|
1211
|
+
? (BUTTON_ICON_SIZES[size] || BUTTON_ICON_SIZES.md)
|
|
1212
|
+
: (BUTTON_SIZES[size] || BUTTON_SIZES.md);
|
|
1213
|
+
|
|
1214
|
+
const disabledClasses = (disabled || loading) ? 'opacity-50 cursor-not-allowed' : '';
|
|
1215
|
+
const widthClasses = fullWidth ? 'w-full' : '';
|
|
1216
|
+
|
|
1217
|
+
const allClasses = cn(BUTTON_BASE_CLASSES, variantClasses, sizeClasses, disabledClasses, widthClasses, className);
|
|
1218
|
+
|
|
1219
|
+
const iconElement = icon ? React.createElement('span', {
|
|
1220
|
+
className: iconPosition === 'left' ? 'mr-2' : 'ml-2'
|
|
1221
|
+
}, icon) : null;
|
|
1222
|
+
|
|
1223
|
+
const loadingSpinner = loading ? React.createElement('span', {
|
|
1224
|
+
className: 'mr-2',
|
|
1225
|
+
dangerouslySetInnerHTML: { __html: LOADING_SPINNER }
|
|
1226
|
+
}) : null;
|
|
1227
|
+
|
|
1228
|
+
return React.createElement('button', {
|
|
1229
|
+
type,
|
|
1230
|
+
className: allClasses,
|
|
1231
|
+
disabled: disabled || loading,
|
|
1232
|
+
onClick
|
|
1233
|
+
},
|
|
1234
|
+
loadingSpinner,
|
|
1235
|
+
!loading && icon && iconPosition === 'left' ? iconElement : null,
|
|
1236
|
+
!iconOnly ? children : null,
|
|
1237
|
+
!loading && icon && iconPosition === 'right' ? iconElement : null
|
|
1238
|
+
);
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
// Badge Component
|
|
1242
|
+
export function Badge(props: any) {
|
|
1243
|
+
const {
|
|
1244
|
+
variant = 'default',
|
|
1245
|
+
size = 'md',
|
|
1246
|
+
pill = false,
|
|
1247
|
+
icon,
|
|
1248
|
+
dot = false,
|
|
1249
|
+
className,
|
|
1250
|
+
removable = false,
|
|
1251
|
+
onRemove,
|
|
1252
|
+
children,
|
|
1253
|
+
} = props;
|
|
1254
|
+
|
|
1255
|
+
// Handle dot badge
|
|
1256
|
+
if (dot) {
|
|
1257
|
+
const dotSizeClasses = BADGE_DOT_SIZES[size] || BADGE_DOT_SIZES.md;
|
|
1258
|
+
const dotVariantClasses = BADGE_DOT_VARIANTS[variant] || BADGE_DOT_VARIANTS.default;
|
|
1259
|
+
const dotClasses = cn('inline-block rounded-full', dotSizeClasses, dotVariantClasses, className);
|
|
1260
|
+
const label = typeof children === 'string' ? children : undefined;
|
|
1261
|
+
return React.createElement('span', {
|
|
1262
|
+
className: dotClasses,
|
|
1263
|
+
'aria-label': label,
|
|
1264
|
+
title: label
|
|
1265
|
+
});
|
|
2108
1266
|
}
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
1267
|
+
|
|
1268
|
+
const variantClasses = BADGE_VARIANTS[variant] || BADGE_VARIANTS.default;
|
|
1269
|
+
const sizeClasses = BADGE_SIZES[size] || BADGE_SIZES.md;
|
|
1270
|
+
|
|
1271
|
+
const baseClasses = cn(
|
|
1272
|
+
'inline-flex items-center font-medium',
|
|
1273
|
+
pill ? 'rounded-full' : 'rounded-md',
|
|
1274
|
+
variantClasses,
|
|
1275
|
+
sizeClasses,
|
|
1276
|
+
className
|
|
1277
|
+
);
|
|
1278
|
+
|
|
1279
|
+
const closeButton = removable ? React.createElement('button', {
|
|
1280
|
+
type: 'button',
|
|
1281
|
+
className: 'ml-1.5 -mr-1 hover:opacity-70 transition-opacity',
|
|
1282
|
+
'aria-label': 'Remove',
|
|
1283
|
+
onClick: onRemove
|
|
1284
|
+
}, React.createElement('svg', {
|
|
1285
|
+
className: 'w-3 h-3',
|
|
1286
|
+
fill: 'none',
|
|
1287
|
+
stroke: 'currentColor',
|
|
1288
|
+
viewBox: '0 0 24 24'
|
|
1289
|
+
}, React.createElement('path', {
|
|
1290
|
+
strokeLinecap: 'round',
|
|
1291
|
+
strokeLinejoin: 'round',
|
|
1292
|
+
strokeWidth: '2',
|
|
1293
|
+
d: 'M6 18L18 6M6 6l12 12'
|
|
1294
|
+
}))) : null;
|
|
1295
|
+
|
|
1296
|
+
return React.createElement('span', { className: baseClasses },
|
|
1297
|
+
icon ? React.createElement('span', { className: 'mr-1' }, icon) : null,
|
|
1298
|
+
children,
|
|
1299
|
+
closeButton
|
|
1300
|
+
);
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
// Alert Component
|
|
1304
|
+
export function Alert(props: any) {
|
|
1305
|
+
const {
|
|
1306
|
+
variant = 'info',
|
|
1307
|
+
title,
|
|
1308
|
+
icon,
|
|
1309
|
+
showIcon = true,
|
|
1310
|
+
dismissible = false,
|
|
1311
|
+
onDismiss,
|
|
1312
|
+
className,
|
|
1313
|
+
children,
|
|
1314
|
+
} = props;
|
|
1315
|
+
|
|
1316
|
+
const variantStyles = ALERT_VARIANTS[variant] || ALERT_VARIANTS.info;
|
|
1317
|
+
const allClasses = cn(ALERT_BASE_CLASSES, variantStyles.container, className);
|
|
1318
|
+
|
|
1319
|
+
const iconContent = icon || (showIcon ? React.createElement('span', {
|
|
1320
|
+
className: cn('flex-shrink-0', variantStyles.icon),
|
|
1321
|
+
dangerouslySetInnerHTML: { __html: ALERT_ICONS[variant] || ALERT_ICONS.info }
|
|
1322
|
+
}) : null);
|
|
1323
|
+
|
|
1324
|
+
const dismissButton = dismissible ? React.createElement('button', {
|
|
1325
|
+
type: 'button',
|
|
1326
|
+
className: 'flex-shrink-0 ml-3 hover:opacity-70 transition-opacity',
|
|
1327
|
+
'aria-label': 'Dismiss',
|
|
1328
|
+
onClick: onDismiss
|
|
1329
|
+
}, React.createElement('span', {
|
|
1330
|
+
dangerouslySetInnerHTML: { __html: CLOSE_ICON }
|
|
1331
|
+
})) : null;
|
|
1332
|
+
|
|
1333
|
+
return React.createElement('div', { className: allClasses, role: 'alert' },
|
|
1334
|
+
React.createElement('div', { className: 'flex' },
|
|
1335
|
+
iconContent ? React.createElement('div', { className: 'flex-shrink-0 mr-3' }, iconContent) : null,
|
|
1336
|
+
React.createElement('div', { className: 'flex-1' },
|
|
1337
|
+
title ? React.createElement('h4', { className: 'font-semibold mb-1' }, title) : null,
|
|
1338
|
+
React.createElement('div', { className: 'text-sm' }, children)
|
|
1339
|
+
),
|
|
1340
|
+
dismissButton
|
|
1341
|
+
)
|
|
1342
|
+
);
|
|
1343
|
+
}
|
|
1344
|
+
`;
|
|
1345
|
+
}
|
|
1346
|
+
function getBrowserRuntimeWrapper() {
|
|
1347
|
+
return `
|
|
1348
|
+
// Assign components to window for require() shim
|
|
1349
|
+
window.Card = Card;
|
|
1350
|
+
window.Button = Button;
|
|
1351
|
+
window.Badge = Badge;
|
|
1352
|
+
window.Alert = Alert;
|
|
1353
|
+
|
|
1354
|
+
// Build the namespace object for @frontmcp/ui/react imports
|
|
1355
|
+
window.frontmcp_ui_namespaceObject = Object.assign({}, window.React || {}, {
|
|
1356
|
+
// Hooks
|
|
1357
|
+
useToolOutput: window.useToolOutput,
|
|
1358
|
+
useToolInput: window.useToolInput,
|
|
1359
|
+
useMcpBridgeContext: function() { return window.__frontmcp.context; },
|
|
1360
|
+
useMcpBridge: function() { return window.__frontmcp.context; },
|
|
1361
|
+
useCallTool: function() {
|
|
1362
|
+
return function(name, args) {
|
|
1363
|
+
if (window.__frontmcp.context && window.__frontmcp.context.callTool) {
|
|
1364
|
+
return window.__frontmcp.context.callTool(name, args);
|
|
1365
|
+
}
|
|
1366
|
+
console.warn('[FrontMCP] callTool not available');
|
|
1367
|
+
return Promise.resolve(null);
|
|
1368
|
+
};
|
|
1369
|
+
},
|
|
1370
|
+
useTheme: function() { return window.__frontmcp.theme || 'light'; },
|
|
1371
|
+
useDisplayMode: function() { return window.__frontmcp.displayMode || 'embedded'; },
|
|
1372
|
+
useHostContext: function() { return window.__frontmcp.hostContext || {}; },
|
|
1373
|
+
useCapability: function(cap) { return window.__frontmcp.capabilities && window.__frontmcp.capabilities[cap] || false; },
|
|
1374
|
+
useStructuredContent: function() { return window.__frontmcp.getState().structuredContent; },
|
|
1375
|
+
useToolCalls: function() { return []; },
|
|
1376
|
+
useSendMessage: function() { return function() { return Promise.resolve(); }; },
|
|
1377
|
+
useOpenLink: function() { return function() {}; },
|
|
1378
|
+
|
|
1379
|
+
// Components
|
|
1380
|
+
Card: window.Card,
|
|
1381
|
+
Badge: window.Badge,
|
|
1382
|
+
Button: window.Button,
|
|
1383
|
+
Alert: window.Alert,
|
|
1384
|
+
|
|
1385
|
+
// Re-export React for convenience
|
|
1386
|
+
createElement: React.createElement,
|
|
1387
|
+
Fragment: React.Fragment,
|
|
1388
|
+
useState: React.useState,
|
|
1389
|
+
useEffect: React.useEffect,
|
|
1390
|
+
useCallback: React.useCallback,
|
|
1391
|
+
useMemo: React.useMemo,
|
|
1392
|
+
useRef: React.useRef,
|
|
1393
|
+
useContext: React.useContext
|
|
1394
|
+
});
|
|
1395
|
+
`;
|
|
1396
|
+
}
|
|
1397
|
+
async function buildWithEsbuild() {
|
|
1398
|
+
try {
|
|
1399
|
+
const esbuild = await import("esbuild");
|
|
1400
|
+
const stylesPath = require.resolve("@frontmcp/uipack/styles");
|
|
1401
|
+
const entrySource = getComponentsEntrySource();
|
|
1402
|
+
const result = await esbuild.build({
|
|
1403
|
+
stdin: {
|
|
1404
|
+
contents: entrySource,
|
|
1405
|
+
loader: "tsx",
|
|
1406
|
+
resolveDir: path.dirname(stylesPath)
|
|
1407
|
+
},
|
|
1408
|
+
bundle: true,
|
|
1409
|
+
format: "iife",
|
|
1410
|
+
globalName: "__frontmcp_components",
|
|
1411
|
+
target: "es2020",
|
|
1412
|
+
minify: false,
|
|
1413
|
+
write: false,
|
|
1414
|
+
external: ["react", "react-dom"],
|
|
1415
|
+
define: {
|
|
1416
|
+
React: "window.React"
|
|
1417
|
+
},
|
|
1418
|
+
platform: "browser"
|
|
1419
|
+
});
|
|
1420
|
+
if (result.outputFiles && result.outputFiles.length > 0) {
|
|
1421
|
+
let code = result.outputFiles[0].text;
|
|
1422
|
+
code += "\n" + getBrowserRuntimeWrapper();
|
|
1423
|
+
return code;
|
|
1424
|
+
}
|
|
1425
|
+
throw new Error("No output from esbuild");
|
|
1426
|
+
} catch (error) {
|
|
1427
|
+
console.warn(
|
|
1428
|
+
`[FrontMCP] esbuild bundle failed, falling back to manual components: ${error instanceof Error ? error.message : String(error)}`
|
|
1429
|
+
);
|
|
1430
|
+
throw error;
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
async function getBrowserComponents() {
|
|
1434
|
+
if (cachedBrowserComponents !== null) {
|
|
1435
|
+
return cachedBrowserComponents;
|
|
1436
|
+
}
|
|
1437
|
+
if (buildingPromise !== null) {
|
|
1438
|
+
return buildingPromise;
|
|
1439
|
+
}
|
|
1440
|
+
buildingPromise = buildWithEsbuild().then((code) => {
|
|
1441
|
+
cachedBrowserComponents = code;
|
|
1442
|
+
buildingPromise = null;
|
|
1443
|
+
return code;
|
|
1444
|
+
}).catch((error) => {
|
|
1445
|
+
buildingPromise = null;
|
|
1446
|
+
throw error;
|
|
1447
|
+
});
|
|
1448
|
+
return buildingPromise;
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
// libs/ui/src/bundler/bundler.ts
|
|
1452
|
+
var import_bundler2 = require("@frontmcp/uipack/bundler");
|
|
1453
|
+
var esbuildTransform = null;
|
|
1454
|
+
async function loadEsbuild() {
|
|
1455
|
+
if (esbuildTransform !== null) {
|
|
1456
|
+
return esbuildTransform;
|
|
1457
|
+
}
|
|
1458
|
+
try {
|
|
1459
|
+
const esbuild = await import("esbuild");
|
|
1460
|
+
esbuildTransform = esbuild.transform;
|
|
1461
|
+
return esbuildTransform;
|
|
1462
|
+
} catch {
|
|
1463
|
+
try {
|
|
1464
|
+
const swc = await import("@swc/core");
|
|
1465
|
+
esbuildTransform = async (source, options) => {
|
|
1466
|
+
const opts = options;
|
|
1467
|
+
const result = await swc.transform(source, {
|
|
1468
|
+
jsc: {
|
|
1469
|
+
parser: {
|
|
1470
|
+
syntax: "typescript",
|
|
2122
1471
|
tsx: opts.loader === "tsx" || opts.loader === "jsx"
|
|
2123
1472
|
},
|
|
2124
1473
|
transform: {
|
|
@@ -2169,11 +1518,11 @@ var InMemoryBundler = class {
|
|
|
2169
1518
|
...options.cache
|
|
2170
1519
|
}
|
|
2171
1520
|
};
|
|
2172
|
-
this.cache = new BundlerCache({
|
|
1521
|
+
this.cache = new import_bundler.BundlerCache({
|
|
2173
1522
|
maxSize: this.options.cache.maxSize,
|
|
2174
1523
|
ttl: this.options.cache.ttl
|
|
2175
1524
|
});
|
|
2176
|
-
this.defaultSecurity = mergePolicy(options.defaultSecurity);
|
|
1525
|
+
this.defaultSecurity = (0, import_bundler.mergePolicy)(options.defaultSecurity);
|
|
2177
1526
|
}
|
|
2178
1527
|
/**
|
|
2179
1528
|
* Bundle source code.
|
|
@@ -2185,7 +1534,7 @@ var InMemoryBundler = class {
|
|
|
2185
1534
|
const startTime = performance.now();
|
|
2186
1535
|
const opts = this.mergeOptions(options);
|
|
2187
1536
|
if (!opts.skipCache && !this.options.cache.disabled) {
|
|
2188
|
-
const cacheKey = options.cacheKey ?? createCacheKey(options.source, opts);
|
|
1537
|
+
const cacheKey = options.cacheKey ?? (0, import_bundler.createCacheKey)(options.source, opts);
|
|
2189
1538
|
const cached = this.cache.get(cacheKey);
|
|
2190
1539
|
if (cached) {
|
|
2191
1540
|
return {
|
|
@@ -2198,18 +1547,18 @@ var InMemoryBundler = class {
|
|
|
2198
1547
|
};
|
|
2199
1548
|
}
|
|
2200
1549
|
}
|
|
2201
|
-
const security = mergePolicy(options.security ?? this.defaultSecurity);
|
|
2202
|
-
const violations = validateSource(options.source, security);
|
|
2203
|
-
throwOnViolations(violations);
|
|
1550
|
+
const security = (0, import_bundler.mergePolicy)(options.security ?? this.defaultSecurity);
|
|
1551
|
+
const violations = (0, import_bundler.validateSource)(options.source, security);
|
|
1552
|
+
(0, import_bundler.throwOnViolations)(violations);
|
|
2204
1553
|
const sourceType = opts.sourceType === "auto" ? this.detectSourceType(options.source) : opts.sourceType;
|
|
2205
1554
|
const transformStart = performance.now();
|
|
2206
1555
|
const transformed = await this.transform(options.source, sourceType, opts);
|
|
2207
1556
|
const transformTime = performance.now() - transformStart;
|
|
2208
|
-
const sizeViolation = validateSize(transformed.code.length, security);
|
|
1557
|
+
const sizeViolation = (0, import_bundler.validateSize)(transformed.code.length, security);
|
|
2209
1558
|
if (sizeViolation) {
|
|
2210
|
-
throwOnViolations([sizeViolation]);
|
|
1559
|
+
(0, import_bundler.throwOnViolations)([sizeViolation]);
|
|
2211
1560
|
}
|
|
2212
|
-
const hash = hashContent(transformed.code);
|
|
1561
|
+
const hash = (0, import_bundler.hashContent)(transformed.code);
|
|
2213
1562
|
const result = {
|
|
2214
1563
|
code: transformed.code,
|
|
2215
1564
|
hash,
|
|
@@ -2226,7 +1575,7 @@ var InMemoryBundler = class {
|
|
|
2226
1575
|
format: opts.format
|
|
2227
1576
|
};
|
|
2228
1577
|
if (!this.options.cache.disabled) {
|
|
2229
|
-
const cacheKey = options.cacheKey ?? createCacheKey(options.source, opts);
|
|
1578
|
+
const cacheKey = options.cacheKey ?? (0, import_bundler.createCacheKey)(options.source, opts);
|
|
2230
1579
|
this.cache.set(cacheKey, result);
|
|
2231
1580
|
}
|
|
2232
1581
|
return result;
|
|
@@ -2253,16 +1602,16 @@ var InMemoryBundler = class {
|
|
|
2253
1602
|
throw new Error("React and react-dom/server are required for SSR. Install them: npm install react react-dom");
|
|
2254
1603
|
}
|
|
2255
1604
|
const renderStart = performance.now();
|
|
2256
|
-
const Component = await executeDefault(bundleResult.code, {
|
|
1605
|
+
const Component = await (0, import_bundler.executeDefault)(bundleResult.code, {
|
|
2257
1606
|
React,
|
|
2258
|
-
security: mergePolicy(options.security ?? this.defaultSecurity)
|
|
1607
|
+
security: (0, import_bundler.mergePolicy)(options.security ?? this.defaultSecurity)
|
|
2259
1608
|
});
|
|
2260
1609
|
let html;
|
|
2261
1610
|
try {
|
|
2262
1611
|
const element = React.createElement(Component, options.context ?? {});
|
|
2263
1612
|
html = ReactDOMServer.renderToString(element);
|
|
2264
1613
|
} catch (error) {
|
|
2265
|
-
throw new ExecutionError(
|
|
1614
|
+
throw new import_bundler.ExecutionError(
|
|
2266
1615
|
`SSR rendering failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
2267
1616
|
error
|
|
2268
1617
|
);
|
|
@@ -2303,10 +1652,10 @@ var InMemoryBundler = class {
|
|
|
2303
1652
|
React = await import("react");
|
|
2304
1653
|
} catch {
|
|
2305
1654
|
}
|
|
2306
|
-
return executeDefault(result.code, {
|
|
1655
|
+
return (0, import_bundler.executeDefault)(result.code, {
|
|
2307
1656
|
React,
|
|
2308
1657
|
globals: context,
|
|
2309
|
-
security: mergePolicy(options.security ?? this.defaultSecurity)
|
|
1658
|
+
security: (0, import_bundler.mergePolicy)(options.security ?? this.defaultSecurity)
|
|
2310
1659
|
});
|
|
2311
1660
|
}
|
|
2312
1661
|
/**
|
|
@@ -2357,10 +1706,19 @@ var InMemoryBundler = class {
|
|
|
2357
1706
|
security: opts.security,
|
|
2358
1707
|
skipCache: opts.skipCache
|
|
2359
1708
|
});
|
|
2360
|
-
const head = this.buildStaticHTMLHead({ externals: opts.externals, customCss: opts.customCss });
|
|
1709
|
+
const head = this.buildStaticHTMLHead({ externals: opts.externals, customCss: opts.customCss, theme: opts.theme });
|
|
2361
1710
|
const reactRuntime = this.buildReactRuntimeScripts(opts.externals, platform, cdnType);
|
|
2362
|
-
const frontmcpRuntime = this.buildFrontMCPRuntime();
|
|
2363
|
-
const dataScript = this.buildDataInjectionScript(
|
|
1711
|
+
const frontmcpRuntime = await this.buildFrontMCPRuntime();
|
|
1712
|
+
const dataScript = this.buildDataInjectionScript(
|
|
1713
|
+
opts.toolName,
|
|
1714
|
+
opts.input,
|
|
1715
|
+
opts.output,
|
|
1716
|
+
opts.structuredContent,
|
|
1717
|
+
opts.buildMode,
|
|
1718
|
+
cdnType,
|
|
1719
|
+
opts.dynamicOptions,
|
|
1720
|
+
opts.hybridOptions
|
|
1721
|
+
);
|
|
2364
1722
|
const componentScript = this.buildComponentRenderScript(bundleResult.code, opts.rootId, cdnType);
|
|
2365
1723
|
const html = this.assembleStaticHTML({
|
|
2366
1724
|
title: opts.title || `${opts.toolName} - Widget`,
|
|
@@ -2372,7 +1730,9 @@ var InMemoryBundler = class {
|
|
|
2372
1730
|
rootId: opts.rootId,
|
|
2373
1731
|
cdnType
|
|
2374
1732
|
});
|
|
2375
|
-
const hash = hashContent(html);
|
|
1733
|
+
const hash = (0, import_bundler.hashContent)(html);
|
|
1734
|
+
const dataPlaceholder = opts.buildMode === "hybrid" ? opts.hybridOptions?.placeholder ?? HYBRID_DATA_PLACEHOLDER : void 0;
|
|
1735
|
+
const inputPlaceholder = opts.buildMode === "hybrid" ? opts.hybridOptions?.inputPlaceholder ?? HYBRID_INPUT_PLACEHOLDER : void 0;
|
|
2376
1736
|
return {
|
|
2377
1737
|
html,
|
|
2378
1738
|
componentCode: bundleResult.code,
|
|
@@ -2384,9 +1744,240 @@ var InMemoryBundler = class {
|
|
|
2384
1744
|
size: html.length,
|
|
2385
1745
|
cached: bundleResult.cached,
|
|
2386
1746
|
sourceType: bundleResult.sourceType,
|
|
2387
|
-
targetPlatform: platform
|
|
1747
|
+
targetPlatform: platform,
|
|
1748
|
+
buildMode: opts.buildMode,
|
|
1749
|
+
dataPlaceholder,
|
|
1750
|
+
inputPlaceholder
|
|
1751
|
+
};
|
|
1752
|
+
}
|
|
1753
|
+
/**
|
|
1754
|
+
* Bundle a component to static HTML for all target platforms at once.
|
|
1755
|
+
*
|
|
1756
|
+
* This method is optimized for efficiency:
|
|
1757
|
+
* - Transpiles the component source code only once
|
|
1758
|
+
* - Generates platform-specific HTML variations from the shared transpiled code
|
|
1759
|
+
* - Returns complete platform metadata ready for MCP responses
|
|
1760
|
+
*
|
|
1761
|
+
* @param options - Multi-platform build options
|
|
1762
|
+
* @returns Multi-platform build result with all platforms
|
|
1763
|
+
*
|
|
1764
|
+
* @example
|
|
1765
|
+
* ```typescript
|
|
1766
|
+
* const result = await bundler.bundleToStaticHTMLAll({
|
|
1767
|
+
* source: `
|
|
1768
|
+
* import { Card, useToolOutput } from '@frontmcp/ui/react';
|
|
1769
|
+
* export default function Weather() {
|
|
1770
|
+
* const output = useToolOutput();
|
|
1771
|
+
* return <Card title="Weather">{output?.temperature}°F</Card>;
|
|
1772
|
+
* }
|
|
1773
|
+
* `,
|
|
1774
|
+
* toolName: 'get_weather',
|
|
1775
|
+
* output: { temperature: 72 },
|
|
1776
|
+
* });
|
|
1777
|
+
*
|
|
1778
|
+
* // Access platform-specific results
|
|
1779
|
+
* const openaiHtml = result.platforms.openai.html;
|
|
1780
|
+
* const claudeHtml = result.platforms.claude.html;
|
|
1781
|
+
*
|
|
1782
|
+
* // Get metadata for MCP response
|
|
1783
|
+
* const openaiMeta = result.platforms.openai.meta;
|
|
1784
|
+
* ```
|
|
1785
|
+
*/
|
|
1786
|
+
async bundleToStaticHTMLAll(options) {
|
|
1787
|
+
const startTime = performance.now();
|
|
1788
|
+
const opts = this.mergeStaticHTMLOptions(options);
|
|
1789
|
+
const platforms = options.platforms ?? [...ALL_PLATFORMS];
|
|
1790
|
+
const transpileStart = performance.now();
|
|
1791
|
+
let transpiledCode = null;
|
|
1792
|
+
let bundleResult = null;
|
|
1793
|
+
const isUniversal = opts.universal;
|
|
1794
|
+
const rawContentType = options.contentType ?? "auto";
|
|
1795
|
+
const contentType = isUniversal ? rawContentType === "auto" ? detectContentType(options.source) : rawContentType : "react";
|
|
1796
|
+
if (contentType === "react" || !isUniversal) {
|
|
1797
|
+
bundleResult = await this.bundle({
|
|
1798
|
+
source: options.source,
|
|
1799
|
+
sourceType: opts.sourceType,
|
|
1800
|
+
format: "cjs",
|
|
1801
|
+
minify: opts.minify,
|
|
1802
|
+
sourceMaps: false,
|
|
1803
|
+
externals: ["react", "react-dom", "react/jsx-runtime", "@frontmcp/ui", "@frontmcp/ui/react"],
|
|
1804
|
+
security: opts.security,
|
|
1805
|
+
skipCache: opts.skipCache
|
|
1806
|
+
});
|
|
1807
|
+
transpiledCode = bundleResult.code;
|
|
1808
|
+
}
|
|
1809
|
+
const transpileTime = performance.now() - transpileStart;
|
|
1810
|
+
const generationStart = performance.now();
|
|
1811
|
+
const platformResults = {};
|
|
1812
|
+
for (const platform of platforms) {
|
|
1813
|
+
const platformResult = await this.buildForPlatform({
|
|
1814
|
+
options,
|
|
1815
|
+
opts,
|
|
1816
|
+
platform,
|
|
1817
|
+
transpiledCode,
|
|
1818
|
+
bundleResult,
|
|
1819
|
+
contentType,
|
|
1820
|
+
isUniversal
|
|
1821
|
+
});
|
|
1822
|
+
platformResults[platform] = platformResult;
|
|
1823
|
+
}
|
|
1824
|
+
const generationTime = performance.now() - generationStart;
|
|
1825
|
+
return {
|
|
1826
|
+
platforms: platformResults,
|
|
1827
|
+
sharedComponentCode: transpiledCode ?? "",
|
|
1828
|
+
metrics: {
|
|
1829
|
+
transpileTime,
|
|
1830
|
+
generationTime,
|
|
1831
|
+
totalTime: performance.now() - startTime
|
|
1832
|
+
},
|
|
1833
|
+
cached: bundleResult?.cached ?? false
|
|
1834
|
+
};
|
|
1835
|
+
}
|
|
1836
|
+
/**
|
|
1837
|
+
* Build for a specific platform with pre-transpiled code.
|
|
1838
|
+
* Internal helper for bundleToStaticHTMLAll.
|
|
1839
|
+
*/
|
|
1840
|
+
async buildForPlatform(params) {
|
|
1841
|
+
const { options, opts, platform, transpiledCode, bundleResult, contentType, isUniversal } = params;
|
|
1842
|
+
const cdnType = getCdnTypeForPlatform(platform);
|
|
1843
|
+
const buildStart = performance.now();
|
|
1844
|
+
let html;
|
|
1845
|
+
let componentCode;
|
|
1846
|
+
if (isUniversal) {
|
|
1847
|
+
const shouldIncludeBridge = opts.buildMode === "dynamic" || opts.buildMode === "hybrid";
|
|
1848
|
+
const cachedRuntime = getCachedRuntime({
|
|
1849
|
+
cdnType,
|
|
1850
|
+
includeMarkdown: opts.includeMarkdown || contentType === "markdown",
|
|
1851
|
+
includeMdx: opts.includeMdx || contentType === "mdx",
|
|
1852
|
+
minify: opts.minify,
|
|
1853
|
+
includeBridge: shouldIncludeBridge
|
|
1854
|
+
});
|
|
1855
|
+
const componentCodeStr = transpiledCode ? buildComponentCode(transpiledCode) : "";
|
|
1856
|
+
const dataInjectionStr = buildDataInjectionCode(
|
|
1857
|
+
opts.toolName,
|
|
1858
|
+
opts.input,
|
|
1859
|
+
opts.output,
|
|
1860
|
+
opts.structuredContent,
|
|
1861
|
+
contentType,
|
|
1862
|
+
transpiledCode ? null : options.source,
|
|
1863
|
+
transpiledCode !== null,
|
|
1864
|
+
{
|
|
1865
|
+
buildMode: opts.buildMode,
|
|
1866
|
+
cdnType,
|
|
1867
|
+
dynamicOptions: opts.dynamicOptions,
|
|
1868
|
+
hybridOptions: opts.hybridOptions
|
|
1869
|
+
}
|
|
1870
|
+
);
|
|
1871
|
+
const appScript = buildAppScript(
|
|
1872
|
+
cachedRuntime.appTemplate,
|
|
1873
|
+
componentCodeStr,
|
|
1874
|
+
dataInjectionStr,
|
|
1875
|
+
opts.customComponents ?? ""
|
|
1876
|
+
);
|
|
1877
|
+
const head = this.buildStaticHTMLHead({
|
|
1878
|
+
externals: opts.externals,
|
|
1879
|
+
customCss: opts.customCss,
|
|
1880
|
+
theme: opts.theme
|
|
1881
|
+
});
|
|
1882
|
+
const reactRuntime = this.buildReactRuntimeScripts(opts.externals, platform, cdnType);
|
|
1883
|
+
const renderScript = this.buildUniversalRenderScript(opts.rootId, cdnType);
|
|
1884
|
+
html = this.assembleUniversalStaticHTMLCached({
|
|
1885
|
+
title: opts.title || `${opts.toolName} - Widget`,
|
|
1886
|
+
head,
|
|
1887
|
+
reactRuntime,
|
|
1888
|
+
cdnImports: cachedRuntime.cdnImports,
|
|
1889
|
+
vendorScript: cachedRuntime.vendorScript,
|
|
1890
|
+
appScript,
|
|
1891
|
+
renderScript,
|
|
1892
|
+
rootId: opts.rootId,
|
|
1893
|
+
cdnType
|
|
1894
|
+
});
|
|
1895
|
+
componentCode = transpiledCode ?? appScript;
|
|
1896
|
+
} else {
|
|
1897
|
+
if (!transpiledCode) {
|
|
1898
|
+
throw new Error("Failed to transpile component source");
|
|
1899
|
+
}
|
|
1900
|
+
const head = this.buildStaticHTMLHead({
|
|
1901
|
+
externals: opts.externals,
|
|
1902
|
+
customCss: opts.customCss,
|
|
1903
|
+
theme: opts.theme
|
|
1904
|
+
});
|
|
1905
|
+
const reactRuntime = this.buildReactRuntimeScripts(opts.externals, platform, cdnType);
|
|
1906
|
+
const frontmcpRuntime = await this.buildFrontMCPRuntime();
|
|
1907
|
+
const dataScript = this.buildDataInjectionScript(
|
|
1908
|
+
opts.toolName,
|
|
1909
|
+
opts.input,
|
|
1910
|
+
opts.output,
|
|
1911
|
+
opts.structuredContent,
|
|
1912
|
+
opts.buildMode,
|
|
1913
|
+
cdnType,
|
|
1914
|
+
opts.dynamicOptions,
|
|
1915
|
+
opts.hybridOptions
|
|
1916
|
+
);
|
|
1917
|
+
const componentScript = this.buildComponentRenderScript(transpiledCode, opts.rootId, cdnType);
|
|
1918
|
+
html = this.assembleStaticHTML({
|
|
1919
|
+
title: opts.title || `${opts.toolName} - Widget`,
|
|
1920
|
+
head,
|
|
1921
|
+
reactRuntime,
|
|
1922
|
+
frontmcpRuntime,
|
|
1923
|
+
dataScript,
|
|
1924
|
+
componentScript,
|
|
1925
|
+
rootId: opts.rootId,
|
|
1926
|
+
cdnType
|
|
1927
|
+
});
|
|
1928
|
+
componentCode = transpiledCode;
|
|
1929
|
+
}
|
|
1930
|
+
const hash = (0, import_bundler.hashContent)(html);
|
|
1931
|
+
const meta = (0, import_adapters.buildUIMeta)({
|
|
1932
|
+
uiConfig: {
|
|
1933
|
+
template: () => html,
|
|
1934
|
+
widgetAccessible: opts.widgetAccessible
|
|
1935
|
+
},
|
|
1936
|
+
platformType: this.mapTargetPlatformToAIPlatform(platform),
|
|
1937
|
+
html
|
|
1938
|
+
});
|
|
1939
|
+
const dataPlaceholder = opts.buildMode === "hybrid" ? opts.hybridOptions?.placeholder ?? HYBRID_DATA_PLACEHOLDER : void 0;
|
|
1940
|
+
const inputPlaceholder = opts.buildMode === "hybrid" ? opts.hybridOptions?.inputPlaceholder ?? HYBRID_INPUT_PLACEHOLDER : void 0;
|
|
1941
|
+
return {
|
|
1942
|
+
html,
|
|
1943
|
+
componentCode,
|
|
1944
|
+
metrics: bundleResult?.metrics ?? {
|
|
1945
|
+
transformTime: 0,
|
|
1946
|
+
bundleTime: 0,
|
|
1947
|
+
totalTime: performance.now() - buildStart
|
|
1948
|
+
},
|
|
1949
|
+
hash,
|
|
1950
|
+
size: html.length,
|
|
1951
|
+
cached: bundleResult?.cached ?? false,
|
|
1952
|
+
sourceType: bundleResult?.sourceType ?? opts.sourceType,
|
|
1953
|
+
targetPlatform: platform,
|
|
1954
|
+
universal: isUniversal,
|
|
1955
|
+
contentType: isUniversal ? contentType : void 0,
|
|
1956
|
+
buildMode: opts.buildMode,
|
|
1957
|
+
dataPlaceholder,
|
|
1958
|
+
inputPlaceholder,
|
|
1959
|
+
meta
|
|
2388
1960
|
};
|
|
2389
1961
|
}
|
|
1962
|
+
/**
|
|
1963
|
+
* Map TargetPlatform to AIPlatformType for metadata generation.
|
|
1964
|
+
*/
|
|
1965
|
+
mapTargetPlatformToAIPlatform(platform) {
|
|
1966
|
+
switch (platform) {
|
|
1967
|
+
case "openai":
|
|
1968
|
+
return "openai";
|
|
1969
|
+
case "claude":
|
|
1970
|
+
return "claude";
|
|
1971
|
+
case "cursor":
|
|
1972
|
+
return "cursor";
|
|
1973
|
+
case "ext-apps":
|
|
1974
|
+
return "ext-apps";
|
|
1975
|
+
case "generic":
|
|
1976
|
+
return "generic-mcp";
|
|
1977
|
+
default:
|
|
1978
|
+
return "generic-mcp";
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
2390
1981
|
/**
|
|
2391
1982
|
* Bundle to static HTML with universal rendering mode.
|
|
2392
1983
|
* Uses the universal renderer that can handle multiple content types.
|
|
@@ -2418,11 +2009,13 @@ var InMemoryBundler = class {
|
|
|
2418
2009
|
transpiledCode = bundleResult.code;
|
|
2419
2010
|
transformTime = bundleResult.metrics.transformTime;
|
|
2420
2011
|
}
|
|
2012
|
+
const shouldIncludeBridge = opts.buildMode === "dynamic" || opts.buildMode === "hybrid";
|
|
2421
2013
|
const cachedRuntime = getCachedRuntime({
|
|
2422
2014
|
cdnType,
|
|
2423
2015
|
includeMarkdown: opts.includeMarkdown || contentType === "markdown",
|
|
2424
2016
|
includeMdx: opts.includeMdx || contentType === "mdx",
|
|
2425
|
-
minify: opts.minify
|
|
2017
|
+
minify: opts.minify,
|
|
2018
|
+
includeBridge: shouldIncludeBridge
|
|
2426
2019
|
});
|
|
2427
2020
|
const componentCodeStr = transpiledCode ? buildComponentCode(transpiledCode) : "";
|
|
2428
2021
|
const dataInjectionStr = buildDataInjectionCode(
|
|
@@ -2433,7 +2026,13 @@ var InMemoryBundler = class {
|
|
|
2433
2026
|
contentType,
|
|
2434
2027
|
transpiledCode ? null : options.source,
|
|
2435
2028
|
// Pass source only if not a component
|
|
2436
|
-
transpiledCode !== null
|
|
2029
|
+
transpiledCode !== null,
|
|
2030
|
+
{
|
|
2031
|
+
buildMode: opts.buildMode,
|
|
2032
|
+
cdnType,
|
|
2033
|
+
dynamicOptions: opts.dynamicOptions,
|
|
2034
|
+
hybridOptions: opts.hybridOptions
|
|
2035
|
+
}
|
|
2437
2036
|
);
|
|
2438
2037
|
const appScript = buildAppScript(
|
|
2439
2038
|
cachedRuntime.appTemplate,
|
|
@@ -2441,7 +2040,7 @@ var InMemoryBundler = class {
|
|
|
2441
2040
|
dataInjectionStr,
|
|
2442
2041
|
opts.customComponents ?? ""
|
|
2443
2042
|
);
|
|
2444
|
-
const head = this.buildStaticHTMLHead({ externals: opts.externals, customCss: opts.customCss });
|
|
2043
|
+
const head = this.buildStaticHTMLHead({ externals: opts.externals, customCss: opts.customCss, theme: opts.theme });
|
|
2445
2044
|
const reactRuntime = this.buildReactRuntimeScripts(opts.externals, platform, cdnType);
|
|
2446
2045
|
const renderScript = this.buildUniversalRenderScript(opts.rootId, cdnType);
|
|
2447
2046
|
const html = this.assembleUniversalStaticHTMLCached({
|
|
@@ -2455,7 +2054,7 @@ var InMemoryBundler = class {
|
|
|
2455
2054
|
rootId: opts.rootId,
|
|
2456
2055
|
cdnType
|
|
2457
2056
|
});
|
|
2458
|
-
const hash = hashContent(html);
|
|
2057
|
+
const hash = (0, import_bundler.hashContent)(html);
|
|
2459
2058
|
return {
|
|
2460
2059
|
html,
|
|
2461
2060
|
componentCode: transpiledCode ?? appScript,
|
|
@@ -2485,7 +2084,7 @@ var InMemoryBundler = class {
|
|
|
2485
2084
|
return `<!DOCTYPE html>
|
|
2486
2085
|
<html lang="en">
|
|
2487
2086
|
<head>
|
|
2488
|
-
<title>${escapeHtml(parts.title)}</title>
|
|
2087
|
+
<title>${(0, import_utils.escapeHtml)(parts.title)}</title>
|
|
2489
2088
|
${parts.head}
|
|
2490
2089
|
${parts.reactRuntime}
|
|
2491
2090
|
${parts.cdnImports}
|
|
@@ -2509,7 +2108,7 @@ ${parts.appScript}
|
|
|
2509
2108
|
return `<!DOCTYPE html>
|
|
2510
2109
|
<html lang="en">
|
|
2511
2110
|
<head>
|
|
2512
|
-
<title>${escapeHtml(parts.title)}</title>
|
|
2111
|
+
<title>${(0, import_utils.escapeHtml)(parts.title)}</title>
|
|
2513
2112
|
${parts.head}
|
|
2514
2113
|
${parts.reactRuntime}
|
|
2515
2114
|
${parts.cdnImports}
|
|
@@ -2691,7 +2290,7 @@ ${parts.appScript}
|
|
|
2691
2290
|
return `<!DOCTYPE html>
|
|
2692
2291
|
<html lang="en">
|
|
2693
2292
|
<head>
|
|
2694
|
-
<title>${escapeHtml(parts.title)}</title>
|
|
2293
|
+
<title>${(0, import_utils.escapeHtml)(parts.title)}</title>
|
|
2695
2294
|
${parts.head}
|
|
2696
2295
|
${parts.reactRuntime}
|
|
2697
2296
|
${parts.frontmcpRuntime ?? ""}
|
|
@@ -2870,6 +2469,10 @@ ${parts.appScript}
|
|
|
2870
2469
|
contentType: options.contentType ?? DEFAULT_STATIC_HTML_OPTIONS.contentType,
|
|
2871
2470
|
includeMarkdown: options.includeMarkdown ?? DEFAULT_STATIC_HTML_OPTIONS.includeMarkdown,
|
|
2872
2471
|
includeMdx: options.includeMdx ?? DEFAULT_STATIC_HTML_OPTIONS.includeMdx,
|
|
2472
|
+
// Build mode options
|
|
2473
|
+
buildMode: options.buildMode ?? DEFAULT_STATIC_HTML_OPTIONS.buildMode,
|
|
2474
|
+
dynamicOptions: options.dynamicOptions,
|
|
2475
|
+
hybridOptions: options.hybridOptions,
|
|
2873
2476
|
// Pass-through options
|
|
2874
2477
|
toolName: options.toolName,
|
|
2875
2478
|
input: options.input,
|
|
@@ -2878,7 +2481,8 @@ ${parts.appScript}
|
|
|
2878
2481
|
title: options.title,
|
|
2879
2482
|
security: options.security,
|
|
2880
2483
|
customCss: options.customCss,
|
|
2881
|
-
customComponents: options.customComponents
|
|
2484
|
+
customComponents: options.customComponents,
|
|
2485
|
+
theme: options.theme
|
|
2882
2486
|
};
|
|
2883
2487
|
}
|
|
2884
2488
|
/**
|
|
@@ -2892,12 +2496,8 @@ ${parts.appScript}
|
|
|
2892
2496
|
parts.push(`<link rel="preconnect" href="${url}" crossorigin>`);
|
|
2893
2497
|
}
|
|
2894
2498
|
parts.push(`<link rel="stylesheet" href="${STATIC_HTML_CDN.fonts.inter}">`);
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
parts.push(`<link rel="stylesheet" href="${STATIC_HTML_CDN.tailwind}">`);
|
|
2898
|
-
} else if (tailwindConfig !== "inline" && tailwindConfig) {
|
|
2899
|
-
parts.push(`<link rel="stylesheet" href="${tailwindConfig}">`);
|
|
2900
|
-
}
|
|
2499
|
+
parts.push((0, import_build2.buildCDNScriptTag)(import_build2.CLOUDFLARE_CDN.tailwindCss));
|
|
2500
|
+
parts.push(this.buildThemeStyleBlock(opts.theme));
|
|
2901
2501
|
parts.push(`<style>
|
|
2902
2502
|
body { margin: 0; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
|
|
2903
2503
|
.frontmcp-loading { display: flex; align-items: center; justify-content: center; min-height: 200px; }
|
|
@@ -2911,6 +2511,18 @@ ${sanitizeCss(opts.customCss)}
|
|
|
2911
2511
|
}
|
|
2912
2512
|
return parts.join("\n ");
|
|
2913
2513
|
}
|
|
2514
|
+
/**
|
|
2515
|
+
* Build theme CSS variables as a :root style block.
|
|
2516
|
+
* Uses DEFAULT_THEME if no theme is provided.
|
|
2517
|
+
*/
|
|
2518
|
+
buildThemeStyleBlock(theme = import_theme.DEFAULT_THEME) {
|
|
2519
|
+
const cssVars = (0, import_theme.buildThemeCss)(theme);
|
|
2520
|
+
return `<style>
|
|
2521
|
+
:root {
|
|
2522
|
+
${cssVars}
|
|
2523
|
+
}
|
|
2524
|
+
</style>`;
|
|
2525
|
+
}
|
|
2914
2526
|
/**
|
|
2915
2527
|
* Build React runtime scripts for static HTML.
|
|
2916
2528
|
*/
|
|
@@ -2975,9 +2587,17 @@ ${sanitizeCss(opts.customCss)}
|
|
|
2975
2587
|
}
|
|
2976
2588
|
/**
|
|
2977
2589
|
* Build FrontMCP runtime (hooks and UI components).
|
|
2590
|
+
* Uses esbuild to transpile real React components at first use, then caches.
|
|
2591
|
+
* Falls back to manual implementation if esbuild fails.
|
|
2978
2592
|
* Always inlined for reliability across platforms.
|
|
2979
2593
|
*/
|
|
2980
|
-
buildFrontMCPRuntime() {
|
|
2594
|
+
async buildFrontMCPRuntime() {
|
|
2595
|
+
let uiComponents;
|
|
2596
|
+
try {
|
|
2597
|
+
uiComponents = await getBrowserComponents();
|
|
2598
|
+
} catch {
|
|
2599
|
+
uiComponents = (0, import_build2.buildUIComponentsRuntime)();
|
|
2600
|
+
}
|
|
2981
2601
|
return `
|
|
2982
2602
|
<!-- FrontMCP Runtime (always inline) -->
|
|
2983
2603
|
<script>
|
|
@@ -2997,8 +2617,8 @@ ${sanitizeCss(opts.customCss)}
|
|
|
2997
2617
|
'react-dom/client': function() { return window.ReactDOM; },
|
|
2998
2618
|
'react/jsx-runtime': function() { return window.jsx_runtime_namespaceObject; },
|
|
2999
2619
|
'react/jsx-dev-runtime': function() { return window.jsx_runtime_namespaceObject; },
|
|
3000
|
-
'@frontmcp/ui': function() { return window.
|
|
3001
|
-
'@frontmcp/ui/react': function() { return window.
|
|
2620
|
+
'@frontmcp/ui': function() { return window.frontmcp_ui_namespaceObject; },
|
|
2621
|
+
'@frontmcp/ui/react': function() { return window.frontmcp_ui_namespaceObject; },
|
|
3002
2622
|
};
|
|
3003
2623
|
|
|
3004
2624
|
var resolver = moduleMap[moduleName];
|
|
@@ -3029,7 +2649,7 @@ ${sanitizeCss(opts.customCss)}
|
|
|
3029
2649
|
});
|
|
3030
2650
|
};
|
|
3031
2651
|
|
|
3032
|
-
// FrontMCP Hook implementations
|
|
2652
|
+
// FrontMCP Hook implementations and state
|
|
3033
2653
|
window.__frontmcp = {
|
|
3034
2654
|
// Context for MCP bridge
|
|
3035
2655
|
context: {
|
|
@@ -3040,10 +2660,35 @@ ${sanitizeCss(opts.customCss)}
|
|
|
3040
2660
|
callTool: null,
|
|
3041
2661
|
},
|
|
3042
2662
|
|
|
2663
|
+
// Theme and display settings
|
|
2664
|
+
theme: 'light',
|
|
2665
|
+
displayMode: 'embedded',
|
|
2666
|
+
hostContext: {},
|
|
2667
|
+
capabilities: {},
|
|
2668
|
+
|
|
3043
2669
|
// Set context from data injection
|
|
3044
2670
|
setContext: function(ctx) {
|
|
3045
2671
|
Object.assign(this.context, ctx);
|
|
3046
2672
|
},
|
|
2673
|
+
|
|
2674
|
+
// State management (for universal mode compatibility)
|
|
2675
|
+
getState: function() {
|
|
2676
|
+
return {
|
|
2677
|
+
toolName: this.context.toolName,
|
|
2678
|
+
input: this.context.toolInput,
|
|
2679
|
+
output: this.context.toolOutput,
|
|
2680
|
+
structuredContent: this.context.structuredContent,
|
|
2681
|
+
loading: false,
|
|
2682
|
+
error: null
|
|
2683
|
+
};
|
|
2684
|
+
},
|
|
2685
|
+
|
|
2686
|
+
setState: function(partial) {
|
|
2687
|
+
if (partial.toolName !== undefined) this.context.toolName = partial.toolName;
|
|
2688
|
+
if (partial.input !== undefined) this.context.toolInput = partial.input;
|
|
2689
|
+
if (partial.output !== undefined) this.context.toolOutput = partial.output;
|
|
2690
|
+
if (partial.structuredContent !== undefined) this.context.structuredContent = partial.structuredContent;
|
|
2691
|
+
}
|
|
3047
2692
|
};
|
|
3048
2693
|
|
|
3049
2694
|
// Hook: useToolOutput - returns the tool output data
|
|
@@ -3071,74 +2716,31 @@ ${sanitizeCss(opts.customCss)}
|
|
|
3071
2716
|
return Promise.resolve(null);
|
|
3072
2717
|
};
|
|
3073
2718
|
};
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
var title = props.title;
|
|
3079
|
-
var className = props.className || '';
|
|
3080
|
-
return React.createElement('div', {
|
|
3081
|
-
className: 'bg-white rounded-lg shadow border border-gray-200 overflow-hidden ' + className
|
|
3082
|
-
}, [
|
|
3083
|
-
title && React.createElement('div', {
|
|
3084
|
-
key: 'header',
|
|
3085
|
-
className: 'px-4 py-3 border-b border-gray-200 bg-gray-50'
|
|
3086
|
-
}, React.createElement('h3', { className: 'text-sm font-medium text-gray-900' }, title)),
|
|
3087
|
-
React.createElement('div', { key: 'body', className: 'p-4' }, children)
|
|
3088
|
-
]);
|
|
3089
|
-
};
|
|
3090
|
-
|
|
3091
|
-
window.Badge = function(props) {
|
|
3092
|
-
var children = props.children;
|
|
3093
|
-
var variant = props.variant || 'default';
|
|
3094
|
-
var variantClasses = {
|
|
3095
|
-
default: 'bg-gray-100 text-gray-800',
|
|
3096
|
-
success: 'bg-green-100 text-green-800',
|
|
3097
|
-
warning: 'bg-yellow-100 text-yellow-800',
|
|
3098
|
-
error: 'bg-red-100 text-red-800',
|
|
3099
|
-
info: 'bg-blue-100 text-blue-800',
|
|
3100
|
-
};
|
|
3101
|
-
return React.createElement('span', {
|
|
3102
|
-
className: 'inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ' + (variantClasses[variant] || variantClasses.default)
|
|
3103
|
-
}, children);
|
|
3104
|
-
};
|
|
3105
|
-
|
|
3106
|
-
window.Button = function(props) {
|
|
3107
|
-
var children = props.children;
|
|
3108
|
-
var variant = props.variant || 'primary';
|
|
3109
|
-
var onClick = props.onClick;
|
|
3110
|
-
var disabled = props.disabled;
|
|
3111
|
-
var variantClasses = {
|
|
3112
|
-
primary: 'bg-blue-600 text-white hover:bg-blue-700',
|
|
3113
|
-
secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
|
|
3114
|
-
outline: 'border border-gray-300 text-gray-700 hover:bg-gray-50',
|
|
3115
|
-
danger: 'bg-red-600 text-white hover:bg-red-700',
|
|
3116
|
-
};
|
|
3117
|
-
return React.createElement('button', {
|
|
3118
|
-
className: 'px-4 py-2 rounded-md text-sm font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 ' +
|
|
3119
|
-
(disabled ? 'opacity-50 cursor-not-allowed ' : '') +
|
|
3120
|
-
(variantClasses[variant] || variantClasses.primary),
|
|
3121
|
-
onClick: onClick,
|
|
3122
|
-
disabled: disabled,
|
|
3123
|
-
}, children);
|
|
3124
|
-
};
|
|
3125
|
-
|
|
3126
|
-
// Make hooks available on react_namespaceObject for bundled imports
|
|
3127
|
-
window.react_namespaceObject = Object.assign({}, window.React || {}, {
|
|
3128
|
-
useToolOutput: window.useToolOutput,
|
|
3129
|
-
useToolInput: window.useToolInput,
|
|
3130
|
-
useMcpBridgeContext: window.useMcpBridgeContext,
|
|
3131
|
-
useCallTool: window.useCallTool,
|
|
3132
|
-
Card: window.Card,
|
|
3133
|
-
Badge: window.Badge,
|
|
3134
|
-
Button: window.Button,
|
|
3135
|
-
});
|
|
2719
|
+
</script>
|
|
2720
|
+
<!-- UI Components (Full-Featured, Browser-Compatible) -->
|
|
2721
|
+
<script>
|
|
2722
|
+
${uiComponents}
|
|
3136
2723
|
</script>`;
|
|
3137
2724
|
}
|
|
3138
2725
|
/**
|
|
3139
2726
|
* Build data injection script for tool input/output.
|
|
2727
|
+
* Dispatches to mode-specific builders based on buildMode.
|
|
2728
|
+
*/
|
|
2729
|
+
buildDataInjectionScript(toolName, input, output, structuredContent, buildMode = "static", cdnType = "esm", dynamicOptions, hybridOptions) {
|
|
2730
|
+
switch (buildMode) {
|
|
2731
|
+
case "dynamic":
|
|
2732
|
+
return this.buildDynamicDataScript(toolName, input, output, structuredContent, cdnType, dynamicOptions);
|
|
2733
|
+
case "hybrid":
|
|
2734
|
+
return this.buildHybridDataScript(toolName, input, structuredContent, hybridOptions);
|
|
2735
|
+
case "static":
|
|
2736
|
+
default:
|
|
2737
|
+
return this.buildStaticDataScript(toolName, input, output, structuredContent);
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
/**
|
|
2741
|
+
* Build static data injection - data baked in at build time (current default).
|
|
3140
2742
|
*/
|
|
3141
|
-
|
|
2743
|
+
buildStaticDataScript(toolName, input, output, structuredContent) {
|
|
3142
2744
|
const safeJson = (value) => {
|
|
3143
2745
|
try {
|
|
3144
2746
|
return JSON.stringify(value);
|
|
@@ -3147,7 +2749,7 @@ ${sanitizeCss(opts.customCss)}
|
|
|
3147
2749
|
}
|
|
3148
2750
|
};
|
|
3149
2751
|
return `
|
|
3150
|
-
<!-- Tool Data Injection -->
|
|
2752
|
+
<!-- Tool Data Injection (Static Mode) -->
|
|
3151
2753
|
<script>
|
|
3152
2754
|
window.__mcpToolName = ${safeJson(toolName)};
|
|
3153
2755
|
window.__mcpToolInput = ${safeJson(input ?? null)};
|
|
@@ -3164,1555 +2766,365 @@ ${sanitizeCss(opts.customCss)}
|
|
|
3164
2766
|
</script>`;
|
|
3165
2767
|
}
|
|
3166
2768
|
/**
|
|
3167
|
-
* Build
|
|
3168
|
-
*
|
|
2769
|
+
* Build dynamic data injection - platform-aware.
|
|
2770
|
+
* For OpenAI (ESM): subscribes to platform events for updates.
|
|
2771
|
+
* For non-OpenAI (UMD/Claude): uses placeholders for data injection.
|
|
3169
2772
|
*/
|
|
3170
|
-
|
|
3171
|
-
const wrappedCode = `
|
|
3172
|
-
// CommonJS module shim
|
|
3173
|
-
var module = { exports: {} };
|
|
3174
|
-
var exports = module.exports;
|
|
3175
|
-
|
|
3176
|
-
// Execute transpiled component code (CommonJS format)
|
|
3177
|
-
${componentCode}
|
|
3178
|
-
|
|
3179
|
-
// Capture the component export
|
|
3180
|
-
window.__frontmcp_component = module.exports;
|
|
3181
|
-
`;
|
|
2773
|
+
buildDynamicDataScript(toolName, input, output, structuredContent, cdnType = "esm", options) {
|
|
3182
2774
|
if (cdnType === "umd") {
|
|
3183
|
-
return
|
|
3184
|
-
|
|
2775
|
+
return this.buildDynamicWithPlaceholdersScript(toolName, structuredContent, options);
|
|
2776
|
+
}
|
|
2777
|
+
return this.buildDynamicWithSubscriptionScript(toolName, input, output, structuredContent, options);
|
|
2778
|
+
}
|
|
2779
|
+
/**
|
|
2780
|
+
* Build dynamic data injection for non-OpenAI platforms using placeholders.
|
|
2781
|
+
* Similar to hybrid mode but with platform-appropriate loading/error states.
|
|
2782
|
+
*/
|
|
2783
|
+
buildDynamicWithPlaceholdersScript(toolName, structuredContent, options) {
|
|
2784
|
+
const safeJson = (value) => {
|
|
2785
|
+
try {
|
|
2786
|
+
return JSON.stringify(value);
|
|
2787
|
+
} catch {
|
|
2788
|
+
return "null";
|
|
2789
|
+
}
|
|
2790
|
+
};
|
|
2791
|
+
const outputPlaceholder = HYBRID_DATA_PLACEHOLDER;
|
|
2792
|
+
const inputPlaceholder = HYBRID_INPUT_PLACEHOLDER;
|
|
2793
|
+
const includeInitialData = options?.includeInitialData !== false;
|
|
2794
|
+
return `
|
|
2795
|
+
<!-- Tool Data Injection (Dynamic Mode - Placeholder-based for non-OpenAI) -->
|
|
3185
2796
|
<script>
|
|
3186
|
-
(
|
|
3187
|
-
|
|
2797
|
+
window.__mcpToolName = ${safeJson(toolName)};
|
|
2798
|
+
window.__mcpToolInput = "${inputPlaceholder}";
|
|
2799
|
+
window.__mcpToolOutput = "${outputPlaceholder}";
|
|
2800
|
+
window.__mcpStructuredContent = ${safeJson(structuredContent ?? null)};
|
|
2801
|
+
window.__mcpHybridError = null;
|
|
3188
2802
|
|
|
3189
|
-
|
|
3190
|
-
var
|
|
2803
|
+
(function() {
|
|
2804
|
+
var outputNotReplaced = false;
|
|
2805
|
+
var includeInitialData = ${includeInitialData};
|
|
3191
2806
|
|
|
3192
|
-
//
|
|
3193
|
-
var
|
|
3194
|
-
if (
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
input: window.__mcpToolInput,
|
|
3206
|
-
}),
|
|
3207
|
-
container
|
|
3208
|
-
);
|
|
2807
|
+
// Parse output placeholder
|
|
2808
|
+
var rawOutput = window.__mcpToolOutput;
|
|
2809
|
+
if (typeof rawOutput === 'string' && rawOutput !== "${outputPlaceholder}") {
|
|
2810
|
+
try {
|
|
2811
|
+
window.__mcpToolOutput = JSON.parse(rawOutput);
|
|
2812
|
+
} catch (e) {
|
|
2813
|
+
console.warn('[FrontMCP] Failed to parse injected output data:', e);
|
|
2814
|
+
window.__mcpToolOutput = null;
|
|
2815
|
+
window.__mcpHybridError = 'Failed to parse output data';
|
|
2816
|
+
}
|
|
2817
|
+
} else if (rawOutput === "${outputPlaceholder}") {
|
|
2818
|
+
window.__mcpToolOutput = null;
|
|
2819
|
+
outputNotReplaced = true;
|
|
3209
2820
|
}
|
|
3210
|
-
})();
|
|
3211
|
-
</script>`;
|
|
3212
|
-
} else {
|
|
3213
|
-
return `
|
|
3214
|
-
<!-- Component Render Script (ESM - waits for React) -->
|
|
3215
|
-
<script type="module">
|
|
3216
|
-
function renderComponent() {
|
|
3217
|
-
${wrappedCode}
|
|
3218
2821
|
|
|
3219
|
-
//
|
|
3220
|
-
var
|
|
2822
|
+
// Parse input placeholder
|
|
2823
|
+
var rawInput = window.__mcpToolInput;
|
|
2824
|
+
if (typeof rawInput === 'string' && rawInput !== "${inputPlaceholder}") {
|
|
2825
|
+
try {
|
|
2826
|
+
window.__mcpToolInput = JSON.parse(rawInput);
|
|
2827
|
+
} catch (e) {
|
|
2828
|
+
console.warn('[FrontMCP] Failed to parse injected input data:', e);
|
|
2829
|
+
window.__mcpToolInput = null;
|
|
2830
|
+
}
|
|
2831
|
+
} else if (rawInput === "${inputPlaceholder}") {
|
|
2832
|
+
window.__mcpToolInput = null;
|
|
2833
|
+
}
|
|
3221
2834
|
|
|
3222
|
-
//
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
var root = window.ReactDOM.createRoot(container);
|
|
3226
|
-
root.render(React.createElement(Component, {
|
|
3227
|
-
output: window.__mcpToolOutput,
|
|
3228
|
-
input: window.__mcpToolInput,
|
|
3229
|
-
}));
|
|
2835
|
+
// Handle placeholder not replaced - show error if expecting initial data
|
|
2836
|
+
if (outputNotReplaced && includeInitialData) {
|
|
2837
|
+
window.__mcpHybridError = 'No data provided. The output placeholder was not replaced.';
|
|
3230
2838
|
}
|
|
3231
|
-
}
|
|
2839
|
+
})();
|
|
3232
2840
|
|
|
3233
|
-
//
|
|
3234
|
-
if (window.
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
2841
|
+
// Initialize FrontMCP context with appropriate loading/error state
|
|
2842
|
+
if (window.__frontmcp && window.__frontmcp.setContext) {
|
|
2843
|
+
window.__frontmcp.setContext({
|
|
2844
|
+
toolName: window.__mcpToolName,
|
|
2845
|
+
toolInput: window.__mcpToolInput,
|
|
2846
|
+
toolOutput: window.__mcpToolOutput,
|
|
2847
|
+
structuredContent: window.__mcpStructuredContent,
|
|
2848
|
+
loading: ${!includeInitialData} && window.__mcpToolOutput === null && !window.__mcpHybridError,
|
|
2849
|
+
error: window.__mcpHybridError,
|
|
2850
|
+
});
|
|
3238
2851
|
}
|
|
3239
2852
|
</script>`;
|
|
3240
|
-
}
|
|
3241
2853
|
}
|
|
3242
2854
|
/**
|
|
3243
|
-
*
|
|
2855
|
+
* Build dynamic data injection for OpenAI using subscription pattern.
|
|
3244
2856
|
*/
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
${parts.reactRuntime}
|
|
3252
|
-
${parts.frontmcpRuntime}
|
|
3253
|
-
${parts.dataScript}
|
|
3254
|
-
</head>
|
|
3255
|
-
<body>
|
|
3256
|
-
<div id="${parts.rootId}" class="frontmcp-loading">
|
|
3257
|
-
<div class="frontmcp-spinner"></div>
|
|
3258
|
-
</div>
|
|
3259
|
-
${parts.componentScript}
|
|
3260
|
-
</body>
|
|
3261
|
-
</html>`;
|
|
3262
|
-
}
|
|
3263
|
-
};
|
|
3264
|
-
function createBundler(options) {
|
|
3265
|
-
return new InMemoryBundler(options);
|
|
3266
|
-
}
|
|
3267
|
-
|
|
3268
|
-
// libs/ui/src/bundler/file-cache/storage/index.ts
|
|
3269
|
-
init_interface();
|
|
3270
|
-
init_filesystem();
|
|
3271
|
-
init_redis();
|
|
3272
|
-
|
|
3273
|
-
// libs/ui/src/bundler/file-cache/hash-calculator.ts
|
|
3274
|
-
var import_crypto2 = require("crypto");
|
|
3275
|
-
var import_promises2 = require("fs/promises");
|
|
3276
|
-
var import_fs2 = require("fs");
|
|
3277
|
-
var import_path2 = require("path");
|
|
3278
|
-
function sha256(content) {
|
|
3279
|
-
return (0, import_crypto2.createHash)("sha256").update(content, "utf8").digest("hex");
|
|
3280
|
-
}
|
|
3281
|
-
function sha256Buffer(buffer) {
|
|
3282
|
-
return (0, import_crypto2.createHash)("sha256").update(buffer).digest("hex");
|
|
3283
|
-
}
|
|
3284
|
-
async function hashFile(filePath) {
|
|
3285
|
-
try {
|
|
3286
|
-
const content = await (0, import_promises2.readFile)(filePath);
|
|
3287
|
-
return sha256Buffer(content);
|
|
3288
|
-
} catch {
|
|
3289
|
-
return void 0;
|
|
3290
|
-
}
|
|
3291
|
-
}
|
|
3292
|
-
async function hashFiles(filePaths) {
|
|
3293
|
-
const hashes = [];
|
|
3294
|
-
for (const filePath of filePaths.sort()) {
|
|
3295
|
-
const hash = await hashFile(filePath);
|
|
3296
|
-
if (hash) {
|
|
3297
|
-
hashes.push(`${filePath}:${hash}`);
|
|
3298
|
-
}
|
|
3299
|
-
}
|
|
3300
|
-
return sha256(hashes.join("\n"));
|
|
3301
|
-
}
|
|
3302
|
-
async function calculateComponentHash(options) {
|
|
3303
|
-
const {
|
|
3304
|
-
entryPath,
|
|
3305
|
-
baseDir = (0, import_path2.dirname)(entryPath),
|
|
3306
|
-
externals = [],
|
|
3307
|
-
dependencies = {},
|
|
3308
|
-
bundleOptions = {},
|
|
3309
|
-
maxDepth = 10
|
|
3310
|
-
} = options;
|
|
3311
|
-
const absoluteEntryPath = (0, import_path2.resolve)(entryPath);
|
|
3312
|
-
const files = /* @__PURE__ */ new Set();
|
|
3313
|
-
const fileHashes = {};
|
|
3314
|
-
await collectLocalDependencies(absoluteEntryPath, baseDir, files, maxDepth, 0);
|
|
3315
|
-
for (const file of files) {
|
|
3316
|
-
const hash = await hashFile(file);
|
|
3317
|
-
if (hash) {
|
|
3318
|
-
fileHashes[file] = hash;
|
|
3319
|
-
}
|
|
3320
|
-
}
|
|
3321
|
-
const sortedFiles = Array.from(files).sort();
|
|
3322
|
-
const fileHashContent = sortedFiles.map((f) => `${f}:${fileHashes[f] || "missing"}`).join("\n");
|
|
3323
|
-
const filesHash = sha256(fileHashContent);
|
|
3324
|
-
const optionsHash = sha256(JSON.stringify(sortedObject(bundleOptions)));
|
|
3325
|
-
const dependenciesHash = sha256(JSON.stringify(sortedObject(dependencies)));
|
|
3326
|
-
const combinedHash = sha256([filesHash, optionsHash, dependenciesHash].join(":"));
|
|
3327
|
-
return {
|
|
3328
|
-
hash: combinedHash,
|
|
3329
|
-
entryHash: fileHashes[absoluteEntryPath] || "",
|
|
3330
|
-
files: sortedFiles,
|
|
3331
|
-
fileHashes,
|
|
3332
|
-
optionsHash,
|
|
3333
|
-
dependenciesHash
|
|
3334
|
-
};
|
|
3335
|
-
}
|
|
3336
|
-
async function calculateQuickHash(entryPath, bundleOptions) {
|
|
3337
|
-
const entryHash = await hashFile(entryPath);
|
|
3338
|
-
const optionsHash = bundleOptions ? sha256(JSON.stringify(sortedObject(bundleOptions))) : "";
|
|
3339
|
-
return sha256(`${entryHash || "missing"}:${optionsHash}`);
|
|
3340
|
-
}
|
|
3341
|
-
async function collectLocalDependencies(filePath, baseDir, collected, maxDepth, currentDepth) {
|
|
3342
|
-
if (currentDepth >= maxDepth) return;
|
|
3343
|
-
if (collected.has(filePath)) return;
|
|
3344
|
-
if (!(0, import_fs2.existsSync)(filePath)) return;
|
|
3345
|
-
collected.add(filePath);
|
|
3346
|
-
try {
|
|
3347
|
-
const content = await (0, import_promises2.readFile)(filePath, "utf8");
|
|
3348
|
-
const imports = extractImportPaths(content);
|
|
3349
|
-
for (const importPath of imports) {
|
|
3350
|
-
if (!importPath.startsWith(".") && !importPath.startsWith("/")) {
|
|
3351
|
-
continue;
|
|
3352
|
-
}
|
|
3353
|
-
const resolvedPath = resolveImportPath(importPath, (0, import_path2.dirname)(filePath));
|
|
3354
|
-
if (resolvedPath && (0, import_fs2.existsSync)(resolvedPath)) {
|
|
3355
|
-
await collectLocalDependencies(resolvedPath, baseDir, collected, maxDepth, currentDepth + 1);
|
|
3356
|
-
}
|
|
3357
|
-
}
|
|
3358
|
-
} catch {
|
|
3359
|
-
}
|
|
3360
|
-
}
|
|
3361
|
-
function extractImportPaths(source) {
|
|
3362
|
-
const paths = [];
|
|
3363
|
-
const importRegex = /import\s+(?:[^'"]+\s+from\s+)?['"]([^'"]+)['"]/g;
|
|
3364
|
-
let match;
|
|
3365
|
-
while ((match = importRegex.exec(source)) !== null) {
|
|
3366
|
-
paths.push(match[1]);
|
|
3367
|
-
}
|
|
3368
|
-
const exportRegex = /export\s+(?:\*|{[^}]+})\s+from\s+['"]([^'"]+)['"]/g;
|
|
3369
|
-
while ((match = exportRegex.exec(source)) !== null) {
|
|
3370
|
-
paths.push(match[1]);
|
|
3371
|
-
}
|
|
3372
|
-
const requireRegex = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
3373
|
-
while ((match = requireRegex.exec(source)) !== null) {
|
|
3374
|
-
paths.push(match[1]);
|
|
3375
|
-
}
|
|
3376
|
-
const dynamicRegex = /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
3377
|
-
while ((match = dynamicRegex.exec(source)) !== null) {
|
|
3378
|
-
paths.push(match[1]);
|
|
3379
|
-
}
|
|
3380
|
-
return [...new Set(paths)];
|
|
3381
|
-
}
|
|
3382
|
-
function resolveImportPath(importPath, fromDir) {
|
|
3383
|
-
const extensions = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
3384
|
-
for (const ext of extensions) {
|
|
3385
|
-
const fullPath = (0, import_path2.join)(fromDir, importPath + ext);
|
|
3386
|
-
if ((0, import_fs2.existsSync)(fullPath)) {
|
|
3387
|
-
return fullPath;
|
|
3388
|
-
}
|
|
3389
|
-
}
|
|
3390
|
-
for (const ext of extensions) {
|
|
3391
|
-
const indexPath = (0, import_path2.join)(fromDir, importPath, `index${ext}`);
|
|
3392
|
-
if ((0, import_fs2.existsSync)(indexPath)) {
|
|
3393
|
-
return indexPath;
|
|
3394
|
-
}
|
|
3395
|
-
}
|
|
3396
|
-
return void 0;
|
|
3397
|
-
}
|
|
3398
|
-
function sortedObject(obj) {
|
|
3399
|
-
const sorted = {};
|
|
3400
|
-
const keys = Object.keys(obj).sort();
|
|
3401
|
-
for (const key of keys) {
|
|
3402
|
-
const value = obj[key];
|
|
3403
|
-
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
3404
|
-
sorted[key] = sortedObject(value);
|
|
3405
|
-
} else {
|
|
3406
|
-
sorted[key] = value;
|
|
3407
|
-
}
|
|
3408
|
-
}
|
|
3409
|
-
return sorted;
|
|
3410
|
-
}
|
|
3411
|
-
function generateBuildId() {
|
|
3412
|
-
const timestamp = Date.now().toString(36);
|
|
3413
|
-
const random = Math.random().toString(36).substring(2, 10);
|
|
3414
|
-
return `${timestamp}-${random}`;
|
|
3415
|
-
}
|
|
3416
|
-
function buildIdFromHash(hash) {
|
|
3417
|
-
return hash.substring(0, 12);
|
|
3418
|
-
}
|
|
3419
|
-
|
|
3420
|
-
// libs/ui/src/bundler/file-cache/component-builder.ts
|
|
3421
|
-
var import_promises3 = require("fs/promises");
|
|
3422
|
-
var import_fs3 = require("fs");
|
|
3423
|
-
var import_path3 = require("path");
|
|
3424
|
-
var import_crypto3 = require("crypto");
|
|
3425
|
-
|
|
3426
|
-
// libs/ui/src/dependency/cdn-registry.ts
|
|
3427
|
-
var DEFAULT_CDN_REGISTRY = {
|
|
3428
|
-
// ============================================
|
|
3429
|
-
// React Ecosystem
|
|
3430
|
-
// ============================================
|
|
3431
|
-
react: {
|
|
3432
|
-
packageName: "react",
|
|
3433
|
-
defaultVersion: "18.3.1",
|
|
3434
|
-
providers: {
|
|
3435
|
-
cloudflare: {
|
|
3436
|
-
url: "https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js",
|
|
3437
|
-
integrity: "sha512-Qp8J4Xr8LBZ5CXNJQc/HmLqFrpXz6lNkbzMYkYHKzQx5p1q1yOqPQHntXKoYgPPE/n9m0QF1OkJdXa2ePpO4fw==",
|
|
3438
|
-
global: "React",
|
|
3439
|
-
crossorigin: "anonymous"
|
|
3440
|
-
},
|
|
3441
|
-
jsdelivr: {
|
|
3442
|
-
url: "https://cdn.jsdelivr.net/npm/react@18.3.1/umd/react.production.min.js",
|
|
3443
|
-
global: "React",
|
|
3444
|
-
crossorigin: "anonymous"
|
|
3445
|
-
},
|
|
3446
|
-
unpkg: {
|
|
3447
|
-
url: "https://unpkg.com/react@18.3.1/umd/react.production.min.js",
|
|
3448
|
-
global: "React",
|
|
3449
|
-
crossorigin: "anonymous"
|
|
3450
|
-
},
|
|
3451
|
-
"esm.sh": {
|
|
3452
|
-
url: "https://esm.sh/react@18.3.1",
|
|
3453
|
-
esm: true,
|
|
3454
|
-
crossorigin: "anonymous"
|
|
3455
|
-
}
|
|
3456
|
-
},
|
|
3457
|
-
preferredProviders: ["cloudflare", "jsdelivr", "unpkg", "esm.sh"],
|
|
3458
|
-
metadata: {
|
|
3459
|
-
description: "A JavaScript library for building user interfaces",
|
|
3460
|
-
homepage: "https://react.dev",
|
|
3461
|
-
license: "MIT"
|
|
3462
|
-
}
|
|
3463
|
-
},
|
|
3464
|
-
"react-dom": {
|
|
3465
|
-
packageName: "react-dom",
|
|
3466
|
-
defaultVersion: "18.3.1",
|
|
3467
|
-
providers: {
|
|
3468
|
-
cloudflare: {
|
|
3469
|
-
url: "https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js",
|
|
3470
|
-
integrity: "sha512-6s2gVRdS3aT+FDdZTRJSzKlzIPqDXWyYl/5hPQb6hSgzKPGFcQyZhbqjbWVxGrs2dYNrINFXb0k0UD3d+CKPJA==",
|
|
3471
|
-
global: "ReactDOM",
|
|
3472
|
-
crossorigin: "anonymous",
|
|
3473
|
-
peerDependencies: ["react"]
|
|
3474
|
-
},
|
|
3475
|
-
jsdelivr: {
|
|
3476
|
-
url: "https://cdn.jsdelivr.net/npm/react-dom@18.3.1/umd/react-dom.production.min.js",
|
|
3477
|
-
global: "ReactDOM",
|
|
3478
|
-
crossorigin: "anonymous",
|
|
3479
|
-
peerDependencies: ["react"]
|
|
3480
|
-
},
|
|
3481
|
-
unpkg: {
|
|
3482
|
-
url: "https://unpkg.com/react-dom@18.3.1/umd/react-dom.production.min.js",
|
|
3483
|
-
global: "ReactDOM",
|
|
3484
|
-
crossorigin: "anonymous",
|
|
3485
|
-
peerDependencies: ["react"]
|
|
3486
|
-
},
|
|
3487
|
-
"esm.sh": {
|
|
3488
|
-
url: "https://esm.sh/react-dom@18.3.1",
|
|
3489
|
-
esm: true,
|
|
3490
|
-
crossorigin: "anonymous",
|
|
3491
|
-
peerDependencies: ["react"]
|
|
3492
|
-
}
|
|
3493
|
-
},
|
|
3494
|
-
preferredProviders: ["cloudflare", "jsdelivr", "unpkg", "esm.sh"],
|
|
3495
|
-
metadata: {
|
|
3496
|
-
description: "React package for working with the DOM",
|
|
3497
|
-
homepage: "https://react.dev",
|
|
3498
|
-
license: "MIT"
|
|
3499
|
-
}
|
|
3500
|
-
},
|
|
3501
|
-
// ============================================
|
|
3502
|
-
// Charting Libraries
|
|
3503
|
-
// ============================================
|
|
3504
|
-
"chart.js": {
|
|
3505
|
-
packageName: "chart.js",
|
|
3506
|
-
defaultVersion: "4.4.7",
|
|
3507
|
-
providers: {
|
|
3508
|
-
cloudflare: {
|
|
3509
|
-
url: "https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.7/chart.umd.min.js",
|
|
3510
|
-
integrity: "sha512-dMDjIoZjJD6gs0KPBhFYjLQrH3kIohSEn6HzWs6Y6GiO0+L9kk/bM3cR5KNEDK1KvMNpTIZG6pHK9SZfCJHRpQ==",
|
|
3511
|
-
global: "Chart",
|
|
3512
|
-
crossorigin: "anonymous"
|
|
3513
|
-
},
|
|
3514
|
-
jsdelivr: {
|
|
3515
|
-
url: "https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js",
|
|
3516
|
-
global: "Chart",
|
|
3517
|
-
crossorigin: "anonymous"
|
|
3518
|
-
},
|
|
3519
|
-
unpkg: {
|
|
3520
|
-
url: "https://unpkg.com/chart.js@4.4.7/dist/chart.umd.min.js",
|
|
3521
|
-
global: "Chart",
|
|
3522
|
-
crossorigin: "anonymous"
|
|
3523
|
-
}
|
|
3524
|
-
},
|
|
3525
|
-
preferredProviders: ["cloudflare", "jsdelivr", "unpkg"],
|
|
3526
|
-
metadata: {
|
|
3527
|
-
description: "Simple yet flexible JavaScript charting library",
|
|
3528
|
-
homepage: "https://www.chartjs.org",
|
|
3529
|
-
license: "MIT"
|
|
3530
|
-
}
|
|
3531
|
-
},
|
|
3532
|
-
"react-chartjs-2": {
|
|
3533
|
-
packageName: "react-chartjs-2",
|
|
3534
|
-
defaultVersion: "5.3.0",
|
|
3535
|
-
providers: {
|
|
3536
|
-
cloudflare: {
|
|
3537
|
-
url: "https://cdnjs.cloudflare.com/ajax/libs/react-chartjs-2/5.3.0/react-chartjs-2.min.js",
|
|
3538
|
-
global: "ReactChartjs2",
|
|
3539
|
-
crossorigin: "anonymous",
|
|
3540
|
-
peerDependencies: ["react", "chart.js"]
|
|
3541
|
-
},
|
|
3542
|
-
jsdelivr: {
|
|
3543
|
-
url: "https://cdn.jsdelivr.net/npm/react-chartjs-2@5.3.0/dist/index.umd.js",
|
|
3544
|
-
global: "ReactChartjs2",
|
|
3545
|
-
crossorigin: "anonymous",
|
|
3546
|
-
peerDependencies: ["react", "chart.js"]
|
|
3547
|
-
},
|
|
3548
|
-
"esm.sh": {
|
|
3549
|
-
url: "https://esm.sh/react-chartjs-2@5.3.0",
|
|
3550
|
-
esm: true,
|
|
3551
|
-
crossorigin: "anonymous",
|
|
3552
|
-
peerDependencies: ["react", "chart.js"]
|
|
3553
|
-
}
|
|
3554
|
-
},
|
|
3555
|
-
preferredProviders: ["cloudflare", "jsdelivr", "esm.sh"],
|
|
3556
|
-
metadata: {
|
|
3557
|
-
description: "React components for Chart.js",
|
|
3558
|
-
homepage: "https://react-chartjs-2.js.org",
|
|
3559
|
-
license: "MIT"
|
|
3560
|
-
}
|
|
3561
|
-
},
|
|
3562
|
-
// ============================================
|
|
3563
|
-
// D3.js
|
|
3564
|
-
// ============================================
|
|
3565
|
-
d3: {
|
|
3566
|
-
packageName: "d3",
|
|
3567
|
-
defaultVersion: "7.9.0",
|
|
3568
|
-
providers: {
|
|
3569
|
-
cloudflare: {
|
|
3570
|
-
url: "https://cdnjs.cloudflare.com/ajax/libs/d3/7.9.0/d3.min.js",
|
|
3571
|
-
integrity: "sha512-vc58qvvBdrDR4etbxMdlTt4GBQk1qjvyORR2nrsPsFPyrs+/u5c3+1Ct6upOgdZoIl7eq6k3a1UPDSNAQi/32A==",
|
|
3572
|
-
global: "d3",
|
|
3573
|
-
crossorigin: "anonymous"
|
|
3574
|
-
},
|
|
3575
|
-
jsdelivr: {
|
|
3576
|
-
url: "https://cdn.jsdelivr.net/npm/d3@7.9.0/dist/d3.min.js",
|
|
3577
|
-
global: "d3",
|
|
3578
|
-
crossorigin: "anonymous"
|
|
3579
|
-
},
|
|
3580
|
-
unpkg: {
|
|
3581
|
-
url: "https://unpkg.com/d3@7.9.0/dist/d3.min.js",
|
|
3582
|
-
global: "d3",
|
|
3583
|
-
crossorigin: "anonymous"
|
|
3584
|
-
}
|
|
3585
|
-
},
|
|
3586
|
-
preferredProviders: ["cloudflare", "jsdelivr", "unpkg"],
|
|
3587
|
-
metadata: {
|
|
3588
|
-
description: "Data-Driven Documents",
|
|
3589
|
-
homepage: "https://d3js.org",
|
|
3590
|
-
license: "ISC"
|
|
3591
|
-
}
|
|
3592
|
-
},
|
|
3593
|
-
// ============================================
|
|
3594
|
-
// Utility Libraries
|
|
3595
|
-
// ============================================
|
|
3596
|
-
lodash: {
|
|
3597
|
-
packageName: "lodash",
|
|
3598
|
-
defaultVersion: "4.17.21",
|
|
3599
|
-
providers: {
|
|
3600
|
-
cloudflare: {
|
|
3601
|
-
url: "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js",
|
|
3602
|
-
integrity: "sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==",
|
|
3603
|
-
global: "_",
|
|
3604
|
-
crossorigin: "anonymous"
|
|
3605
|
-
},
|
|
3606
|
-
jsdelivr: {
|
|
3607
|
-
url: "https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js",
|
|
3608
|
-
global: "_",
|
|
3609
|
-
crossorigin: "anonymous"
|
|
3610
|
-
},
|
|
3611
|
-
unpkg: {
|
|
3612
|
-
url: "https://unpkg.com/lodash@4.17.21/lodash.min.js",
|
|
3613
|
-
global: "_",
|
|
3614
|
-
crossorigin: "anonymous"
|
|
3615
|
-
}
|
|
3616
|
-
},
|
|
3617
|
-
preferredProviders: ["cloudflare", "jsdelivr", "unpkg"],
|
|
3618
|
-
metadata: {
|
|
3619
|
-
description: "A modern JavaScript utility library",
|
|
3620
|
-
homepage: "https://lodash.com",
|
|
3621
|
-
license: "MIT"
|
|
3622
|
-
}
|
|
3623
|
-
},
|
|
3624
|
-
"lodash-es": {
|
|
3625
|
-
packageName: "lodash-es",
|
|
3626
|
-
defaultVersion: "4.17.21",
|
|
3627
|
-
providers: {
|
|
3628
|
-
"esm.sh": {
|
|
3629
|
-
url: "https://esm.sh/lodash-es@4.17.21",
|
|
3630
|
-
esm: true,
|
|
3631
|
-
crossorigin: "anonymous"
|
|
3632
|
-
},
|
|
3633
|
-
jsdelivr: {
|
|
3634
|
-
url: "https://cdn.jsdelivr.net/npm/lodash-es@4.17.21/+esm",
|
|
3635
|
-
esm: true,
|
|
3636
|
-
crossorigin: "anonymous"
|
|
3637
|
-
}
|
|
3638
|
-
},
|
|
3639
|
-
preferredProviders: ["esm.sh", "jsdelivr"],
|
|
3640
|
-
metadata: {
|
|
3641
|
-
description: "Lodash exported as ES modules",
|
|
3642
|
-
homepage: "https://lodash.com",
|
|
3643
|
-
license: "MIT"
|
|
3644
|
-
}
|
|
3645
|
-
},
|
|
3646
|
-
dayjs: {
|
|
3647
|
-
packageName: "dayjs",
|
|
3648
|
-
defaultVersion: "1.11.13",
|
|
3649
|
-
providers: {
|
|
3650
|
-
cloudflare: {
|
|
3651
|
-
url: "https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.11.13/dayjs.min.js",
|
|
3652
|
-
integrity: "sha512-Ot7ArUEhJDU0cwoBNNnWe487kjL5wAOsIYig8llY/l0P2TUFwgsAHVmrZMHsT8NGo+HwkjTJsNErS6QqIkBxDw==",
|
|
3653
|
-
global: "dayjs",
|
|
3654
|
-
crossorigin: "anonymous"
|
|
3655
|
-
},
|
|
3656
|
-
jsdelivr: {
|
|
3657
|
-
url: "https://cdn.jsdelivr.net/npm/dayjs@1.11.13/dayjs.min.js",
|
|
3658
|
-
global: "dayjs",
|
|
3659
|
-
crossorigin: "anonymous"
|
|
3660
|
-
},
|
|
3661
|
-
unpkg: {
|
|
3662
|
-
url: "https://unpkg.com/dayjs@1.11.13/dayjs.min.js",
|
|
3663
|
-
global: "dayjs",
|
|
3664
|
-
crossorigin: "anonymous"
|
|
3665
|
-
}
|
|
3666
|
-
},
|
|
3667
|
-
preferredProviders: ["cloudflare", "jsdelivr", "unpkg"],
|
|
3668
|
-
metadata: {
|
|
3669
|
-
description: "Fast 2kB alternative to Moment.js with the same modern API",
|
|
3670
|
-
homepage: "https://day.js.org",
|
|
3671
|
-
license: "MIT"
|
|
3672
|
-
}
|
|
3673
|
-
},
|
|
3674
|
-
"date-fns": {
|
|
3675
|
-
packageName: "date-fns",
|
|
3676
|
-
defaultVersion: "4.1.0",
|
|
3677
|
-
providers: {
|
|
3678
|
-
"esm.sh": {
|
|
3679
|
-
url: "https://esm.sh/date-fns@4.1.0",
|
|
3680
|
-
esm: true,
|
|
3681
|
-
crossorigin: "anonymous"
|
|
3682
|
-
},
|
|
3683
|
-
jsdelivr: {
|
|
3684
|
-
url: "https://cdn.jsdelivr.net/npm/date-fns@4.1.0/+esm",
|
|
3685
|
-
esm: true,
|
|
3686
|
-
crossorigin: "anonymous"
|
|
3687
|
-
}
|
|
3688
|
-
},
|
|
3689
|
-
preferredProviders: ["esm.sh", "jsdelivr"],
|
|
3690
|
-
metadata: {
|
|
3691
|
-
description: "Modern JavaScript date utility library",
|
|
3692
|
-
homepage: "https://date-fns.org",
|
|
3693
|
-
license: "MIT"
|
|
3694
|
-
}
|
|
3695
|
-
},
|
|
3696
|
-
// ============================================
|
|
3697
|
-
// Animation Libraries
|
|
3698
|
-
// ============================================
|
|
3699
|
-
"framer-motion": {
|
|
3700
|
-
packageName: "framer-motion",
|
|
3701
|
-
defaultVersion: "11.15.0",
|
|
3702
|
-
providers: {
|
|
3703
|
-
"esm.sh": {
|
|
3704
|
-
url: "https://esm.sh/framer-motion@11.15.0",
|
|
3705
|
-
esm: true,
|
|
3706
|
-
crossorigin: "anonymous",
|
|
3707
|
-
peerDependencies: ["react", "react-dom"]
|
|
3708
|
-
},
|
|
3709
|
-
jsdelivr: {
|
|
3710
|
-
url: "https://cdn.jsdelivr.net/npm/framer-motion@11.15.0/dist/framer-motion.js",
|
|
3711
|
-
global: "Motion",
|
|
3712
|
-
crossorigin: "anonymous",
|
|
3713
|
-
peerDependencies: ["react", "react-dom"]
|
|
3714
|
-
}
|
|
3715
|
-
},
|
|
3716
|
-
preferredProviders: ["esm.sh", "jsdelivr"],
|
|
3717
|
-
metadata: {
|
|
3718
|
-
description: "Production-ready motion library for React",
|
|
3719
|
-
homepage: "https://www.framer.com/motion/",
|
|
3720
|
-
license: "MIT"
|
|
3721
|
-
}
|
|
3722
|
-
},
|
|
3723
|
-
// ============================================
|
|
3724
|
-
// UI Component Libraries
|
|
3725
|
-
// ============================================
|
|
3726
|
-
"lucide-react": {
|
|
3727
|
-
packageName: "lucide-react",
|
|
3728
|
-
defaultVersion: "0.468.0",
|
|
3729
|
-
providers: {
|
|
3730
|
-
"esm.sh": {
|
|
3731
|
-
url: "https://esm.sh/lucide-react@0.468.0",
|
|
3732
|
-
esm: true,
|
|
3733
|
-
crossorigin: "anonymous",
|
|
3734
|
-
peerDependencies: ["react"]
|
|
3735
|
-
},
|
|
3736
|
-
jsdelivr: {
|
|
3737
|
-
url: "https://cdn.jsdelivr.net/npm/lucide-react@0.468.0/dist/esm/lucide-react.js",
|
|
3738
|
-
esm: true,
|
|
3739
|
-
crossorigin: "anonymous",
|
|
3740
|
-
peerDependencies: ["react"]
|
|
3741
|
-
}
|
|
3742
|
-
},
|
|
3743
|
-
preferredProviders: ["esm.sh", "jsdelivr"],
|
|
3744
|
-
metadata: {
|
|
3745
|
-
description: "Beautiful & consistent icon toolkit for React",
|
|
3746
|
-
homepage: "https://lucide.dev",
|
|
3747
|
-
license: "ISC"
|
|
3748
|
-
}
|
|
3749
|
-
},
|
|
3750
|
-
// ============================================
|
|
3751
|
-
// Markdown/Syntax Highlighting
|
|
3752
|
-
// ============================================
|
|
3753
|
-
marked: {
|
|
3754
|
-
packageName: "marked",
|
|
3755
|
-
defaultVersion: "15.0.4",
|
|
3756
|
-
providers: {
|
|
3757
|
-
cloudflare: {
|
|
3758
|
-
url: "https://cdnjs.cloudflare.com/ajax/libs/marked/15.0.4/marked.min.js",
|
|
3759
|
-
integrity: "sha512-Rn/d0sGeizGbk3VJEiYNDt/mMcfuzYoFkia3iBffv+HX8VUrHMo/0cKjZuxWGoZLPh/VxUcC9ais+RBFZW9EBg==",
|
|
3760
|
-
global: "marked",
|
|
3761
|
-
crossorigin: "anonymous"
|
|
3762
|
-
},
|
|
3763
|
-
jsdelivr: {
|
|
3764
|
-
url: "https://cdn.jsdelivr.net/npm/marked@15.0.4/marked.min.js",
|
|
3765
|
-
global: "marked",
|
|
3766
|
-
crossorigin: "anonymous"
|
|
3767
|
-
},
|
|
3768
|
-
unpkg: {
|
|
3769
|
-
url: "https://unpkg.com/marked@15.0.4/marked.min.js",
|
|
3770
|
-
global: "marked",
|
|
3771
|
-
crossorigin: "anonymous"
|
|
3772
|
-
}
|
|
3773
|
-
},
|
|
3774
|
-
preferredProviders: ["cloudflare", "jsdelivr", "unpkg"],
|
|
3775
|
-
metadata: {
|
|
3776
|
-
description: "A markdown parser and compiler",
|
|
3777
|
-
homepage: "https://marked.js.org",
|
|
3778
|
-
license: "MIT"
|
|
3779
|
-
}
|
|
3780
|
-
},
|
|
3781
|
-
"highlight.js": {
|
|
3782
|
-
packageName: "highlight.js",
|
|
3783
|
-
defaultVersion: "11.10.0",
|
|
3784
|
-
providers: {
|
|
3785
|
-
cloudflare: {
|
|
3786
|
-
url: "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.10.0/highlight.min.js",
|
|
3787
|
-
integrity: "sha512-6yoqbrcLAHDWAdQmiRlHG4+m0g/CT/V9AGyxabG8j7Jk8j3v3k6mIP1iN/PvSofcWet2tf8SRn/j3L/+pb7LRQ==",
|
|
3788
|
-
global: "hljs",
|
|
3789
|
-
crossorigin: "anonymous"
|
|
3790
|
-
},
|
|
3791
|
-
jsdelivr: {
|
|
3792
|
-
url: "https://cdn.jsdelivr.net/npm/highlight.js@11.10.0/lib/core.min.js",
|
|
3793
|
-
global: "hljs",
|
|
3794
|
-
crossorigin: "anonymous"
|
|
3795
|
-
},
|
|
3796
|
-
unpkg: {
|
|
3797
|
-
url: "https://unpkg.com/highlight.js@11.10.0/lib/core.min.js",
|
|
3798
|
-
global: "hljs",
|
|
3799
|
-
crossorigin: "anonymous"
|
|
3800
|
-
}
|
|
3801
|
-
},
|
|
3802
|
-
preferredProviders: ["cloudflare", "jsdelivr", "unpkg"],
|
|
3803
|
-
metadata: {
|
|
3804
|
-
description: "Syntax highlighting for the web",
|
|
3805
|
-
homepage: "https://highlightjs.org",
|
|
3806
|
-
license: "BSD-3-Clause"
|
|
3807
|
-
}
|
|
3808
|
-
},
|
|
3809
|
-
// ============================================
|
|
3810
|
-
// Interactive Libraries
|
|
3811
|
-
// ============================================
|
|
3812
|
-
"htmx.org": {
|
|
3813
|
-
packageName: "htmx.org",
|
|
3814
|
-
defaultVersion: "2.0.4",
|
|
3815
|
-
providers: {
|
|
3816
|
-
cloudflare: {
|
|
3817
|
-
url: "https://cdnjs.cloudflare.com/ajax/libs/htmx/2.0.4/htmx.min.js",
|
|
3818
|
-
integrity: "sha512-2kIcAizYXhIn5IyXrMC72f2nh0JAtESHRpOieVw5dYPYeHwLCC2eKCqvdZDYRSEgasKrPpEPpRFjL8gqwBZWAA==",
|
|
3819
|
-
global: "htmx",
|
|
3820
|
-
crossorigin: "anonymous"
|
|
3821
|
-
},
|
|
3822
|
-
jsdelivr: {
|
|
3823
|
-
url: "https://cdn.jsdelivr.net/npm/htmx.org@2.0.4/dist/htmx.min.js",
|
|
3824
|
-
global: "htmx",
|
|
3825
|
-
crossorigin: "anonymous"
|
|
3826
|
-
},
|
|
3827
|
-
unpkg: {
|
|
3828
|
-
url: "https://unpkg.com/htmx.org@2.0.4/dist/htmx.min.js",
|
|
3829
|
-
global: "htmx",
|
|
3830
|
-
crossorigin: "anonymous"
|
|
3831
|
-
}
|
|
3832
|
-
},
|
|
3833
|
-
preferredProviders: ["cloudflare", "jsdelivr", "unpkg"],
|
|
3834
|
-
metadata: {
|
|
3835
|
-
description: "High power tools for HTML",
|
|
3836
|
-
homepage: "https://htmx.org",
|
|
3837
|
-
license: "BSD-2-Clause"
|
|
3838
|
-
}
|
|
3839
|
-
},
|
|
3840
|
-
alpinejs: {
|
|
3841
|
-
packageName: "alpinejs",
|
|
3842
|
-
defaultVersion: "3.14.3",
|
|
3843
|
-
providers: {
|
|
3844
|
-
cloudflare: {
|
|
3845
|
-
url: "https://cdnjs.cloudflare.com/ajax/libs/alpinejs/3.14.3/cdn.min.js",
|
|
3846
|
-
integrity: "sha512-lrQ8FHgsWKFSuQFq8NKPJicjlvJFEIrCqEj8zeX7ZOUlHWltN/Iow4jND+x84jqTdDf9n+hvQpJjGDvOl/eDRA==",
|
|
3847
|
-
global: "Alpine",
|
|
3848
|
-
crossorigin: "anonymous"
|
|
3849
|
-
},
|
|
3850
|
-
jsdelivr: {
|
|
3851
|
-
url: "https://cdn.jsdelivr.net/npm/alpinejs@3.14.3/dist/cdn.min.js",
|
|
3852
|
-
global: "Alpine",
|
|
3853
|
-
crossorigin: "anonymous"
|
|
3854
|
-
},
|
|
3855
|
-
unpkg: {
|
|
3856
|
-
url: "https://unpkg.com/alpinejs@3.14.3/dist/cdn.min.js",
|
|
3857
|
-
global: "Alpine",
|
|
3858
|
-
crossorigin: "anonymous"
|
|
3859
|
-
}
|
|
3860
|
-
},
|
|
3861
|
-
preferredProviders: ["cloudflare", "jsdelivr", "unpkg"],
|
|
3862
|
-
metadata: {
|
|
3863
|
-
description: "A rugged, minimal framework for composing behavior directly in your markup",
|
|
3864
|
-
homepage: "https://alpinejs.dev",
|
|
3865
|
-
license: "MIT"
|
|
3866
|
-
}
|
|
3867
|
-
},
|
|
3868
|
-
// ============================================
|
|
3869
|
-
// Templating Libraries
|
|
3870
|
-
// ============================================
|
|
3871
|
-
handlebars: {
|
|
3872
|
-
packageName: "handlebars",
|
|
3873
|
-
defaultVersion: "4.7.8",
|
|
3874
|
-
providers: {
|
|
3875
|
-
cloudflare: {
|
|
3876
|
-
url: "https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.8/handlebars.min.js",
|
|
3877
|
-
integrity: "sha512-E1dSFxg+wsfJ4HKjutk/WaCzK7S2wv1POn1RRPGh8ZK+ag9l244Vqxji3r6wgz9YBf6+vhQEYJZpSjqWFPg9gg==",
|
|
3878
|
-
global: "Handlebars",
|
|
3879
|
-
crossorigin: "anonymous"
|
|
3880
|
-
},
|
|
3881
|
-
jsdelivr: {
|
|
3882
|
-
url: "https://cdn.jsdelivr.net/npm/handlebars@4.7.8/dist/handlebars.min.js",
|
|
3883
|
-
global: "Handlebars",
|
|
3884
|
-
crossorigin: "anonymous"
|
|
3885
|
-
},
|
|
3886
|
-
unpkg: {
|
|
3887
|
-
url: "https://unpkg.com/handlebars@4.7.8/dist/handlebars.min.js",
|
|
3888
|
-
global: "Handlebars",
|
|
3889
|
-
crossorigin: "anonymous"
|
|
3890
|
-
}
|
|
3891
|
-
},
|
|
3892
|
-
preferredProviders: ["cloudflare", "jsdelivr", "unpkg"],
|
|
3893
|
-
metadata: {
|
|
3894
|
-
description: "Minimal templating on steroids",
|
|
3895
|
-
homepage: "https://handlebarsjs.com",
|
|
3896
|
-
license: "MIT"
|
|
3897
|
-
}
|
|
3898
|
-
}
|
|
3899
|
-
};
|
|
3900
|
-
var CDN_PROVIDER_PRIORITY = {
|
|
3901
|
-
claude: ["cloudflare"],
|
|
3902
|
-
// ONLY cloudflare for Claude
|
|
3903
|
-
openai: ["cloudflare", "jsdelivr", "unpkg", "esm.sh"],
|
|
3904
|
-
cursor: ["cloudflare", "jsdelivr", "unpkg", "esm.sh"],
|
|
3905
|
-
gemini: ["cloudflare", "jsdelivr", "unpkg", "esm.sh"],
|
|
3906
|
-
continue: ["cloudflare", "jsdelivr", "unpkg", "esm.sh"],
|
|
3907
|
-
cody: ["cloudflare", "jsdelivr", "unpkg", "esm.sh"],
|
|
3908
|
-
unknown: ["cloudflare", "jsdelivr", "unpkg", "esm.sh"]
|
|
3909
|
-
// Default to cloudflare first
|
|
3910
|
-
};
|
|
3911
|
-
function lookupPackage(packageName, registry = DEFAULT_CDN_REGISTRY) {
|
|
3912
|
-
return registry[packageName];
|
|
3913
|
-
}
|
|
3914
|
-
function mergeRegistries(customRegistry) {
|
|
3915
|
-
return {
|
|
3916
|
-
...DEFAULT_CDN_REGISTRY,
|
|
3917
|
-
...customRegistry
|
|
3918
|
-
};
|
|
3919
|
-
}
|
|
3920
|
-
function getPackagePeerDependencies(packageName, registry = DEFAULT_CDN_REGISTRY) {
|
|
3921
|
-
const entry = lookupPackage(packageName, registry);
|
|
3922
|
-
if (!entry) return [];
|
|
3923
|
-
for (const provider of Object.keys(entry.providers)) {
|
|
3924
|
-
const config = entry.providers[provider];
|
|
3925
|
-
if (config?.peerDependencies) {
|
|
3926
|
-
return config.peerDependencies;
|
|
3927
|
-
}
|
|
3928
|
-
}
|
|
3929
|
-
return [];
|
|
3930
|
-
}
|
|
3931
|
-
function resolveAllDependencies(packageNames, platform = "unknown", registry = DEFAULT_CDN_REGISTRY) {
|
|
3932
|
-
const resolved = /* @__PURE__ */ new Set();
|
|
3933
|
-
const queue = [...packageNames];
|
|
3934
|
-
while (queue.length > 0) {
|
|
3935
|
-
const packageName = queue.shift();
|
|
3936
|
-
if (!packageName) continue;
|
|
3937
|
-
if (resolved.has(packageName)) continue;
|
|
3938
|
-
resolved.add(packageName);
|
|
3939
|
-
const peers = getPackagePeerDependencies(packageName, registry);
|
|
3940
|
-
for (const peer of peers) {
|
|
3941
|
-
if (!resolved.has(peer)) {
|
|
3942
|
-
queue.push(peer);
|
|
3943
|
-
}
|
|
3944
|
-
}
|
|
3945
|
-
}
|
|
3946
|
-
const result = [];
|
|
3947
|
-
const remaining = new Set(resolved);
|
|
3948
|
-
while (remaining.size > 0) {
|
|
3949
|
-
let added = false;
|
|
3950
|
-
for (const pkg of remaining) {
|
|
3951
|
-
const peers = getPackagePeerDependencies(pkg, registry);
|
|
3952
|
-
const allPeersResolved = peers.every((peer) => !remaining.has(peer) || result.includes(peer));
|
|
3953
|
-
if (allPeersResolved) {
|
|
3954
|
-
if (!result.includes(pkg)) {
|
|
3955
|
-
result.push(pkg);
|
|
3956
|
-
}
|
|
3957
|
-
remaining.delete(pkg);
|
|
3958
|
-
added = true;
|
|
3959
|
-
}
|
|
3960
|
-
}
|
|
3961
|
-
if (!added && remaining.size > 0) {
|
|
3962
|
-
const next = remaining.values().next().value;
|
|
3963
|
-
if (next !== void 0) {
|
|
3964
|
-
if (!result.includes(next)) {
|
|
3965
|
-
result.push(next);
|
|
3966
|
-
}
|
|
3967
|
-
remaining.delete(next);
|
|
3968
|
-
}
|
|
3969
|
-
}
|
|
3970
|
-
}
|
|
3971
|
-
return result;
|
|
3972
|
-
}
|
|
3973
|
-
|
|
3974
|
-
// libs/ui/src/dependency/import-parser.ts
|
|
3975
|
-
var IMPORT_PATTERNS = {
|
|
3976
|
-
/**
|
|
3977
|
-
* Named imports: import { foo, bar } from 'module'
|
|
3978
|
-
* Also handles renamed imports: import { foo as f } from 'module'
|
|
3979
|
-
*/
|
|
3980
|
-
named: /import\s*\{([^}]+)\}\s*from\s*['"]([^'"]+)['"]/g,
|
|
3981
|
-
/**
|
|
3982
|
-
* Default imports: import foo from 'module'
|
|
3983
|
-
*/
|
|
3984
|
-
default: /import\s+(\w+)\s+from\s*['"]([^'"]+)['"]/g,
|
|
3985
|
-
/**
|
|
3986
|
-
* Namespace imports: import * as foo from 'module'
|
|
3987
|
-
*/
|
|
3988
|
-
namespace: /import\s*\*\s*as\s+(\w+)\s+from\s*['"]([^'"]+)['"]/g,
|
|
3989
|
-
/**
|
|
3990
|
-
* Side-effect imports: import 'module'
|
|
3991
|
-
*/
|
|
3992
|
-
sideEffect: /import\s*['"]([^'"]+)['"]/g,
|
|
3993
|
-
/**
|
|
3994
|
-
* Dynamic imports: import('module') or await import('module')
|
|
3995
|
-
*/
|
|
3996
|
-
dynamic: /(?:await\s+)?import\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
3997
|
-
/**
|
|
3998
|
-
* Combined default and named: import foo, { bar } from 'module'
|
|
3999
|
-
*/
|
|
4000
|
-
defaultAndNamed: /import\s+(\w+)\s*,\s*\{([^}]+)\}\s*from\s*['"]([^'"]+)['"]/g,
|
|
4001
|
-
/**
|
|
4002
|
-
* Combined default and namespace: import foo, * as bar from 'module'
|
|
4003
|
-
*/
|
|
4004
|
-
defaultAndNamespace: /import\s+(\w+)\s*,\s*\*\s*as\s+(\w+)\s+from\s*['"]([^'"]+)['"]/g,
|
|
4005
|
-
/**
|
|
4006
|
-
* Re-exports: export { foo } from 'module'
|
|
4007
|
-
*/
|
|
4008
|
-
reExport: /export\s*\{[^}]+\}\s*from\s*['"]([^'"]+)['"]/g,
|
|
4009
|
-
/**
|
|
4010
|
-
* Re-export all: export * from 'module'
|
|
4011
|
-
*/
|
|
4012
|
-
reExportAll: /export\s*\*\s*from\s*['"]([^'"]+)['"]/g
|
|
4013
|
-
};
|
|
4014
|
-
function parseNamedImports(namedString) {
|
|
4015
|
-
return namedString.split(",").map((s) => s.trim()).filter((s) => s.length > 0).map((s) => {
|
|
4016
|
-
const asMatch = s.match(/^(\w+)\s+as\s+\w+$/);
|
|
4017
|
-
return asMatch ? asMatch[1] : s;
|
|
4018
|
-
});
|
|
4019
|
-
}
|
|
4020
|
-
function isRelativeImport(specifier) {
|
|
4021
|
-
return specifier.startsWith("./") || specifier.startsWith("../") || specifier.startsWith("/");
|
|
4022
|
-
}
|
|
4023
|
-
function isExternalImport(specifier) {
|
|
4024
|
-
return !isRelativeImport(specifier) && !specifier.startsWith("#");
|
|
4025
|
-
}
|
|
4026
|
-
function getPackageName(specifier) {
|
|
4027
|
-
if (specifier.startsWith("@")) {
|
|
4028
|
-
const parts = specifier.split("/");
|
|
4029
|
-
if (parts.length >= 2) {
|
|
4030
|
-
return `${parts[0]}/${parts[1]}`;
|
|
4031
|
-
}
|
|
4032
|
-
return specifier;
|
|
4033
|
-
}
|
|
4034
|
-
const firstSlash = specifier.indexOf("/");
|
|
4035
|
-
return firstSlash === -1 ? specifier : specifier.slice(0, firstSlash);
|
|
4036
|
-
}
|
|
4037
|
-
function getLineNumber(source, index) {
|
|
4038
|
-
let line = 1;
|
|
4039
|
-
for (let i = 0; i < index && i < source.length; i++) {
|
|
4040
|
-
if (source[i] === "\n") {
|
|
4041
|
-
line++;
|
|
4042
|
-
}
|
|
4043
|
-
}
|
|
4044
|
-
return line;
|
|
4045
|
-
}
|
|
4046
|
-
function getColumnNumber(source, index) {
|
|
4047
|
-
let column = 0;
|
|
4048
|
-
for (let i = index - 1; i >= 0 && source[i] !== "\n"; i--) {
|
|
4049
|
-
column++;
|
|
4050
|
-
}
|
|
4051
|
-
return column;
|
|
4052
|
-
}
|
|
4053
|
-
function parseImports(source) {
|
|
4054
|
-
const imports = [];
|
|
4055
|
-
const seenStatements = /* @__PURE__ */ new Set();
|
|
4056
|
-
const addImport = (imp) => {
|
|
4057
|
-
const key = `${imp.type}:${imp.specifier}:${imp.statement}`;
|
|
4058
|
-
if (!seenStatements.has(key)) {
|
|
4059
|
-
seenStatements.add(key);
|
|
4060
|
-
imports.push(imp);
|
|
4061
|
-
}
|
|
4062
|
-
};
|
|
4063
|
-
let match;
|
|
4064
|
-
const defaultAndNamedRegex = new RegExp(IMPORT_PATTERNS.defaultAndNamed.source, "g");
|
|
4065
|
-
while ((match = defaultAndNamedRegex.exec(source)) !== null) {
|
|
4066
|
-
const [statement, defaultName, namedString, specifier] = match;
|
|
4067
|
-
const namedImports = parseNamedImports(namedString);
|
|
4068
|
-
addImport({
|
|
4069
|
-
statement,
|
|
4070
|
-
specifier,
|
|
4071
|
-
type: "default",
|
|
4072
|
-
defaultImport: defaultName,
|
|
4073
|
-
namedImports,
|
|
4074
|
-
line: getLineNumber(source, match.index),
|
|
4075
|
-
column: getColumnNumber(source, match.index)
|
|
4076
|
-
});
|
|
4077
|
-
}
|
|
4078
|
-
const defaultAndNamespaceRegex = new RegExp(IMPORT_PATTERNS.defaultAndNamespace.source, "g");
|
|
4079
|
-
while ((match = defaultAndNamespaceRegex.exec(source)) !== null) {
|
|
4080
|
-
const [statement, defaultName, namespaceName, specifier] = match;
|
|
4081
|
-
addImport({
|
|
4082
|
-
statement,
|
|
4083
|
-
specifier,
|
|
4084
|
-
type: "default",
|
|
4085
|
-
defaultImport: defaultName,
|
|
4086
|
-
namespaceImport: namespaceName,
|
|
4087
|
-
line: getLineNumber(source, match.index),
|
|
4088
|
-
column: getColumnNumber(source, match.index)
|
|
4089
|
-
});
|
|
4090
|
-
}
|
|
4091
|
-
const namedRegex = new RegExp(IMPORT_PATTERNS.named.source, "g");
|
|
4092
|
-
while ((match = namedRegex.exec(source)) !== null) {
|
|
4093
|
-
const [statement, namedString, specifier] = match;
|
|
4094
|
-
const namedImports = parseNamedImports(namedString);
|
|
4095
|
-
addImport({
|
|
4096
|
-
statement,
|
|
4097
|
-
specifier,
|
|
4098
|
-
type: "named",
|
|
4099
|
-
namedImports,
|
|
4100
|
-
line: getLineNumber(source, match.index),
|
|
4101
|
-
column: getColumnNumber(source, match.index)
|
|
4102
|
-
});
|
|
4103
|
-
}
|
|
4104
|
-
const defaultRegex = new RegExp(IMPORT_PATTERNS.default.source, "g");
|
|
4105
|
-
while ((match = defaultRegex.exec(source)) !== null) {
|
|
4106
|
-
const [statement, defaultName, specifier] = match;
|
|
4107
|
-
const afterMatch = source.slice(match.index + match[0].length - specifier.length - 2);
|
|
4108
|
-
if (afterMatch.startsWith(",")) continue;
|
|
4109
|
-
addImport({
|
|
4110
|
-
statement,
|
|
4111
|
-
specifier,
|
|
4112
|
-
type: "default",
|
|
4113
|
-
defaultImport: defaultName,
|
|
4114
|
-
line: getLineNumber(source, match.index),
|
|
4115
|
-
column: getColumnNumber(source, match.index)
|
|
4116
|
-
});
|
|
4117
|
-
}
|
|
4118
|
-
const namespaceRegex = new RegExp(IMPORT_PATTERNS.namespace.source, "g");
|
|
4119
|
-
while ((match = namespaceRegex.exec(source)) !== null) {
|
|
4120
|
-
const [statement, namespaceName, specifier] = match;
|
|
4121
|
-
addImport({
|
|
4122
|
-
statement,
|
|
4123
|
-
specifier,
|
|
4124
|
-
type: "namespace",
|
|
4125
|
-
namespaceImport: namespaceName,
|
|
4126
|
-
line: getLineNumber(source, match.index),
|
|
4127
|
-
column: getColumnNumber(source, match.index)
|
|
4128
|
-
});
|
|
4129
|
-
}
|
|
4130
|
-
const sideEffectRegex = new RegExp(IMPORT_PATTERNS.sideEffect.source, "g");
|
|
4131
|
-
while ((match = sideEffectRegex.exec(source)) !== null) {
|
|
4132
|
-
const [statement, specifier] = match;
|
|
4133
|
-
const beforeMatch = source.slice(Math.max(0, match.index - 50), match.index);
|
|
4134
|
-
if (beforeMatch.includes("from")) continue;
|
|
4135
|
-
addImport({
|
|
4136
|
-
statement,
|
|
4137
|
-
specifier,
|
|
4138
|
-
type: "side-effect",
|
|
4139
|
-
line: getLineNumber(source, match.index),
|
|
4140
|
-
column: getColumnNumber(source, match.index)
|
|
4141
|
-
});
|
|
4142
|
-
}
|
|
4143
|
-
const dynamicRegex = new RegExp(IMPORT_PATTERNS.dynamic.source, "g");
|
|
4144
|
-
while ((match = dynamicRegex.exec(source)) !== null) {
|
|
4145
|
-
const [statement, specifier] = match;
|
|
4146
|
-
addImport({
|
|
4147
|
-
statement,
|
|
4148
|
-
specifier,
|
|
4149
|
-
type: "dynamic",
|
|
4150
|
-
line: getLineNumber(source, match.index),
|
|
4151
|
-
column: getColumnNumber(source, match.index)
|
|
4152
|
-
});
|
|
4153
|
-
}
|
|
4154
|
-
const reExportRegex = new RegExp(IMPORT_PATTERNS.reExport.source, "g");
|
|
4155
|
-
while ((match = reExportRegex.exec(source)) !== null) {
|
|
4156
|
-
const [statement, specifier] = match;
|
|
4157
|
-
addImport({
|
|
4158
|
-
statement,
|
|
4159
|
-
specifier,
|
|
4160
|
-
type: "named",
|
|
4161
|
-
line: getLineNumber(source, match.index),
|
|
4162
|
-
column: getColumnNumber(source, match.index)
|
|
4163
|
-
});
|
|
4164
|
-
}
|
|
4165
|
-
const reExportAllRegex = new RegExp(IMPORT_PATTERNS.reExportAll.source, "g");
|
|
4166
|
-
while ((match = reExportAllRegex.exec(source)) !== null) {
|
|
4167
|
-
const [statement, specifier] = match;
|
|
4168
|
-
addImport({
|
|
4169
|
-
statement,
|
|
4170
|
-
specifier,
|
|
4171
|
-
type: "namespace",
|
|
4172
|
-
line: getLineNumber(source, match.index),
|
|
4173
|
-
column: getColumnNumber(source, match.index)
|
|
4174
|
-
});
|
|
4175
|
-
}
|
|
4176
|
-
const externalImports = imports.filter((imp) => isExternalImport(imp.specifier));
|
|
4177
|
-
const relativeImports = imports.filter((imp) => isRelativeImport(imp.specifier));
|
|
4178
|
-
const externalPackages = [...new Set(externalImports.map((imp) => getPackageName(imp.specifier)))];
|
|
4179
|
-
return {
|
|
4180
|
-
imports,
|
|
4181
|
-
externalImports,
|
|
4182
|
-
relativeImports,
|
|
4183
|
-
externalPackages
|
|
4184
|
-
};
|
|
4185
|
-
}
|
|
4186
|
-
|
|
4187
|
-
// libs/ui/src/dependency/import-map.ts
|
|
4188
|
-
function createImportMap(dependencies) {
|
|
4189
|
-
const imports = {};
|
|
4190
|
-
const integrity = {};
|
|
4191
|
-
for (const dep of dependencies) {
|
|
4192
|
-
imports[dep.packageName] = dep.cdnUrl;
|
|
4193
|
-
if (dep.integrity) {
|
|
4194
|
-
integrity[dep.cdnUrl] = dep.integrity;
|
|
4195
|
-
}
|
|
4196
|
-
}
|
|
4197
|
-
return {
|
|
4198
|
-
imports,
|
|
4199
|
-
integrity: Object.keys(integrity).length > 0 ? integrity : void 0
|
|
4200
|
-
};
|
|
4201
|
-
}
|
|
4202
|
-
function generateImportMapScriptTag(map) {
|
|
4203
|
-
const json = JSON.stringify(map, null, 2);
|
|
4204
|
-
return `<script type="importmap">
|
|
4205
|
-
${json}
|
|
4206
|
-
</script>`;
|
|
4207
|
-
}
|
|
4208
|
-
function generateImportMapScriptTagMinified(map) {
|
|
4209
|
-
const json = JSON.stringify(map);
|
|
4210
|
-
return `<script type="importmap">${json}</script>`;
|
|
4211
|
-
}
|
|
4212
|
-
function generateUMDShim(dependencies, options = {}) {
|
|
4213
|
-
const { safe = true, minify = false } = options;
|
|
4214
|
-
const depsWithGlobals = dependencies.filter((d) => d.global && !d.esm);
|
|
4215
|
-
if (depsWithGlobals.length === 0) {
|
|
4216
|
-
return "";
|
|
4217
|
-
}
|
|
4218
|
-
const entries = depsWithGlobals.map((dep) => {
|
|
4219
|
-
const global = dep.global;
|
|
4220
|
-
return `'${dep.packageName}': { default: window.${global}, ...window.${global} }`;
|
|
4221
|
-
});
|
|
4222
|
-
const shimObject = `{
|
|
4223
|
-
${entries.join(",\n ")}
|
|
4224
|
-
}`;
|
|
4225
|
-
const code = safe ? `(function() {
|
|
4226
|
-
try {
|
|
4227
|
-
window.__esm_shim = ${shimObject};
|
|
4228
|
-
} catch (e) {
|
|
4229
|
-
console.warn('UMD shim failed:', e);
|
|
4230
|
-
}
|
|
4231
|
-
})();` : `window.__esm_shim = ${shimObject};`;
|
|
4232
|
-
return minify ? code.replace(/\s+/g, " ").replace(/\s*([{},:])\s*/g, "$1") : code;
|
|
4233
|
-
}
|
|
4234
|
-
function generateCDNScriptTags(dependencies) {
|
|
4235
|
-
return dependencies.filter((dep) => !dep.esm).map((dep) => {
|
|
4236
|
-
const attrs = [`src="${escapeHtmlAttr(dep.cdnUrl)}"`];
|
|
4237
|
-
if (dep.integrity) {
|
|
4238
|
-
attrs.push(`integrity="${escapeHtmlAttr(dep.integrity)}"`);
|
|
4239
|
-
}
|
|
4240
|
-
attrs.push('crossorigin="anonymous"');
|
|
4241
|
-
return `<script ${attrs.join(" ")}></script>`;
|
|
4242
|
-
});
|
|
4243
|
-
}
|
|
4244
|
-
function generateESMScriptTags(dependencies) {
|
|
4245
|
-
return dependencies.filter((dep) => dep.esm).map((dep) => {
|
|
4246
|
-
const attrs = ['type="module"', `src="${escapeHtmlAttr(dep.cdnUrl)}"`];
|
|
4247
|
-
if (dep.integrity) {
|
|
4248
|
-
attrs.push(`integrity="${escapeHtmlAttr(dep.integrity)}"`);
|
|
4249
|
-
}
|
|
4250
|
-
attrs.push('crossorigin="anonymous"');
|
|
4251
|
-
return `<script ${attrs.join(" ")}></script>`;
|
|
4252
|
-
});
|
|
4253
|
-
}
|
|
4254
|
-
function generateDependencyHTML(dependencies, options = {}) {
|
|
4255
|
-
const { minify = false, includeShim = true } = options;
|
|
4256
|
-
const parts = [];
|
|
4257
|
-
const importMap = createImportMap(dependencies);
|
|
4258
|
-
const importMapTag = minify ? generateImportMapScriptTagMinified(importMap) : generateImportMapScriptTag(importMap);
|
|
4259
|
-
parts.push(importMapTag);
|
|
4260
|
-
const umdTags = generateCDNScriptTags(dependencies);
|
|
4261
|
-
parts.push(...umdTags);
|
|
4262
|
-
if (includeShim) {
|
|
4263
|
-
const shim = generateUMDShim(dependencies, { minify });
|
|
4264
|
-
if (shim) {
|
|
4265
|
-
parts.push(`<script>${shim}</script>`);
|
|
4266
|
-
}
|
|
4267
|
-
}
|
|
4268
|
-
const esmTags = generateESMScriptTags(dependencies);
|
|
4269
|
-
parts.push(...esmTags);
|
|
4270
|
-
return parts.join(minify ? "" : "\n");
|
|
4271
|
-
}
|
|
4272
|
-
|
|
4273
|
-
// libs/ui/src/dependency/resolver.ts
|
|
4274
|
-
var DependencyResolutionError = class extends Error {
|
|
4275
|
-
constructor(packageName, reason) {
|
|
4276
|
-
super(`Failed to resolve dependency "${packageName}": ${reason}`);
|
|
4277
|
-
this.packageName = packageName;
|
|
4278
|
-
this.reason = reason;
|
|
4279
|
-
this.name = "DependencyResolutionError";
|
|
4280
|
-
}
|
|
4281
|
-
};
|
|
4282
|
-
var NoProviderError = class extends DependencyResolutionError {
|
|
4283
|
-
constructor(packageName, platform) {
|
|
4284
|
-
super(packageName, `No CDN provider available for platform "${platform}"`);
|
|
4285
|
-
this.platform = platform;
|
|
4286
|
-
this.name = "NoProviderError";
|
|
4287
|
-
}
|
|
4288
|
-
};
|
|
4289
|
-
var DependencyResolver = class {
|
|
4290
|
-
options;
|
|
4291
|
-
registry;
|
|
4292
|
-
constructor(options = {}) {
|
|
4293
|
-
this.options = {
|
|
4294
|
-
platform: options.platform ?? "unknown",
|
|
4295
|
-
preferredProviders: options.preferredProviders ?? CDN_PROVIDER_PRIORITY[options.platform ?? "unknown"],
|
|
4296
|
-
customRegistry: options.customRegistry ?? {},
|
|
4297
|
-
strictMode: options.strictMode ?? true,
|
|
4298
|
-
requireIntegrity: options.requireIntegrity ?? false
|
|
4299
|
-
};
|
|
4300
|
-
this.registry = mergeRegistries(this.options.customRegistry);
|
|
4301
|
-
}
|
|
4302
|
-
/**
|
|
4303
|
-
* Resolve a single package to its CDN dependency.
|
|
4304
|
-
*
|
|
4305
|
-
* @param packageName - NPM package name
|
|
4306
|
-
* @param override - Optional explicit CDN dependency override
|
|
4307
|
-
* @returns Resolved dependency, or null in non-strict mode if package is not found (should be bundled)
|
|
4308
|
-
* @throws DependencyResolutionError if package cannot be resolved in strict mode
|
|
4309
|
-
*/
|
|
4310
|
-
resolve(packageName, override) {
|
|
4311
|
-
if (override) {
|
|
4312
|
-
return this.createResolvedDependency(packageName, override, "custom");
|
|
4313
|
-
}
|
|
4314
|
-
const entry = lookupPackage(packageName, this.registry);
|
|
4315
|
-
if (!entry) {
|
|
4316
|
-
if (this.options.strictMode) {
|
|
4317
|
-
throw new DependencyResolutionError(
|
|
4318
|
-
packageName,
|
|
4319
|
-
'Package not found in CDN registry. Add it to "dependencies" for explicit CDN configuration.'
|
|
4320
|
-
);
|
|
2857
|
+
buildDynamicWithSubscriptionScript(toolName, input, output, structuredContent, options) {
|
|
2858
|
+
const safeJson = (value) => {
|
|
2859
|
+
try {
|
|
2860
|
+
return JSON.stringify(value);
|
|
2861
|
+
} catch {
|
|
2862
|
+
return "null";
|
|
4321
2863
|
}
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
const
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
if (
|
|
4328
|
-
|
|
4329
|
-
|
|
2864
|
+
};
|
|
2865
|
+
const includeInitial = options?.includeInitialData !== false;
|
|
2866
|
+
const subscribeToUpdates = options?.subscribeToUpdates !== false;
|
|
2867
|
+
const initialDataBlock = includeInitial ? `
|
|
2868
|
+
window.__mcpToolOutput = ${safeJson(output ?? null)};
|
|
2869
|
+
if (window.__frontmcp && window.__frontmcp.setState) {
|
|
2870
|
+
window.__frontmcp.setState({
|
|
2871
|
+
output: window.__mcpToolOutput,
|
|
2872
|
+
loading: false,
|
|
2873
|
+
});
|
|
2874
|
+
}` : `
|
|
2875
|
+
window.__mcpToolOutput = null;
|
|
2876
|
+
if (window.__frontmcp && window.__frontmcp.setState) {
|
|
2877
|
+
window.__frontmcp.setState({
|
|
2878
|
+
output: null,
|
|
2879
|
+
loading: true,
|
|
2880
|
+
});
|
|
2881
|
+
}`;
|
|
2882
|
+
const subscriptionBlock = subscribeToUpdates ? `
|
|
2883
|
+
// Subscribe to platform tool result updates
|
|
2884
|
+
(function() {
|
|
2885
|
+
function subscribeToUpdates() {
|
|
2886
|
+
// OpenAI Apps SDK
|
|
2887
|
+
if (window.openai && window.openai.canvas && window.openai.canvas.onToolResult) {
|
|
2888
|
+
window.openai.canvas.onToolResult(function(result) {
|
|
2889
|
+
window.__mcpToolOutput = result;
|
|
2890
|
+
if (window.__frontmcp && window.__frontmcp.setState) {
|
|
2891
|
+
window.__frontmcp.setState({
|
|
2892
|
+
output: result,
|
|
2893
|
+
loading: false,
|
|
2894
|
+
});
|
|
2895
|
+
}
|
|
2896
|
+
// Dispatch custom event for React hooks
|
|
2897
|
+
window.dispatchEvent(new CustomEvent('frontmcp:toolResult', { detail: result }));
|
|
2898
|
+
});
|
|
2899
|
+
return;
|
|
2900
|
+
}
|
|
2901
|
+
|
|
2902
|
+
// Fallback: listen for custom events (for testing/other platforms)
|
|
2903
|
+
window.addEventListener('frontmcp:injectData', function(e) {
|
|
2904
|
+
if (e.detail && e.detail.output !== undefined) {
|
|
2905
|
+
window.__mcpToolOutput = e.detail.output;
|
|
2906
|
+
if (window.__frontmcp && window.__frontmcp.setState) {
|
|
2907
|
+
window.__frontmcp.setState({
|
|
2908
|
+
output: e.detail.output,
|
|
2909
|
+
loading: false,
|
|
2910
|
+
});
|
|
2911
|
+
}
|
|
2912
|
+
}
|
|
2913
|
+
});
|
|
4330
2914
|
}
|
|
4331
|
-
|
|
2915
|
+
|
|
2916
|
+
// Subscribe when DOM is ready
|
|
2917
|
+
if (document.readyState === 'loading') {
|
|
2918
|
+
document.addEventListener('DOMContentLoaded', subscribeToUpdates);
|
|
2919
|
+
} else {
|
|
2920
|
+
subscribeToUpdates();
|
|
2921
|
+
}
|
|
2922
|
+
})();` : "";
|
|
2923
|
+
return `
|
|
2924
|
+
<!-- Tool Data Injection (Dynamic Mode - OpenAI Subscription) -->
|
|
2925
|
+
<script>
|
|
2926
|
+
window.__mcpToolName = ${safeJson(toolName)};
|
|
2927
|
+
window.__mcpToolInput = ${safeJson(input ?? null)};
|
|
2928
|
+
window.__mcpStructuredContent = ${safeJson(structuredContent ?? null)};
|
|
2929
|
+
${initialDataBlock}
|
|
2930
|
+
|
|
2931
|
+
// Initialize FrontMCP context
|
|
2932
|
+
if (window.__frontmcp && window.__frontmcp.setContext) {
|
|
2933
|
+
window.__frontmcp.setContext({
|
|
2934
|
+
toolName: window.__mcpToolName,
|
|
2935
|
+
toolInput: window.__mcpToolInput,
|
|
2936
|
+
toolOutput: window.__mcpToolOutput,
|
|
2937
|
+
structuredContent: window.__mcpStructuredContent,
|
|
2938
|
+
});
|
|
4332
2939
|
}
|
|
4333
|
-
|
|
4334
|
-
|
|
2940
|
+
${subscriptionBlock}
|
|
2941
|
+
</script>`;
|
|
4335
2942
|
}
|
|
4336
2943
|
/**
|
|
4337
|
-
*
|
|
4338
|
-
*
|
|
4339
|
-
* @param packageNames - Array of package names
|
|
4340
|
-
* @param overrides - Optional explicit overrides for specific packages
|
|
4341
|
-
* @returns Array of resolved dependencies (in dependency order)
|
|
2944
|
+
* Build hybrid data injection - shell with placeholders for runtime injection.
|
|
2945
|
+
* Use injectHybridData() or injectHybridDataFull() from @frontmcp/uipack to replace the placeholders.
|
|
4342
2946
|
*/
|
|
4343
|
-
|
|
4344
|
-
const
|
|
4345
|
-
const resolved = [];
|
|
4346
|
-
for (const pkgName of allPackages) {
|
|
2947
|
+
buildHybridDataScript(toolName, _input, structuredContent, options) {
|
|
2948
|
+
const safeJson = (value) => {
|
|
4347
2949
|
try {
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
resolved.push(dep);
|
|
4352
|
-
}
|
|
4353
|
-
} catch (error) {
|
|
4354
|
-
if (this.options.strictMode) {
|
|
4355
|
-
throw error;
|
|
4356
|
-
}
|
|
2950
|
+
return JSON.stringify(value);
|
|
2951
|
+
} catch {
|
|
2952
|
+
return "null";
|
|
4357
2953
|
}
|
|
4358
|
-
}
|
|
4359
|
-
return resolved;
|
|
4360
|
-
}
|
|
4361
|
-
/**
|
|
4362
|
-
* Resolve dependencies from source code.
|
|
4363
|
-
*
|
|
4364
|
-
* Parses the source to extract imports, then resolves external packages
|
|
4365
|
-
* that are in the externals list.
|
|
4366
|
-
*
|
|
4367
|
-
* @param source - Source code to parse
|
|
4368
|
-
* @param externals - Package names to resolve from CDN (others are bundled)
|
|
4369
|
-
* @param overrides - Optional explicit CDN overrides
|
|
4370
|
-
* @returns Resolved dependencies
|
|
4371
|
-
*/
|
|
4372
|
-
resolveFromSource(source, externals, overrides) {
|
|
4373
|
-
const parseResult = parseImports(source);
|
|
4374
|
-
const packagesToResolve = parseResult.externalPackages.filter((pkg) => externals.includes(pkg));
|
|
4375
|
-
return this.resolveMany(packagesToResolve, overrides);
|
|
4376
|
-
}
|
|
4377
|
-
/**
|
|
4378
|
-
* Generate an import map for resolved dependencies.
|
|
4379
|
-
*
|
|
4380
|
-
* @param dependencies - Resolved dependencies
|
|
4381
|
-
* @returns Browser import map
|
|
4382
|
-
*/
|
|
4383
|
-
generateImportMap(dependencies) {
|
|
4384
|
-
return createImportMap(dependencies);
|
|
4385
|
-
}
|
|
4386
|
-
/**
|
|
4387
|
-
* Check if a package can be resolved for the current platform.
|
|
4388
|
-
*
|
|
4389
|
-
* @param packageName - Package name to check
|
|
4390
|
-
* @returns true if the package can be resolved
|
|
4391
|
-
*/
|
|
4392
|
-
canResolve(packageName) {
|
|
4393
|
-
try {
|
|
4394
|
-
const result = this.resolve(packageName);
|
|
4395
|
-
return result !== null;
|
|
4396
|
-
} catch {
|
|
4397
|
-
return false;
|
|
4398
|
-
}
|
|
4399
|
-
}
|
|
4400
|
-
/**
|
|
4401
|
-
* Get the resolved CDN URL for a package.
|
|
4402
|
-
*
|
|
4403
|
-
* @param packageName - Package name
|
|
4404
|
-
* @param override - Optional explicit override
|
|
4405
|
-
* @returns CDN URL or undefined if cannot resolve
|
|
4406
|
-
*/
|
|
4407
|
-
getUrl(packageName, override) {
|
|
4408
|
-
try {
|
|
4409
|
-
const resolved = this.resolve(packageName, override);
|
|
4410
|
-
return resolved?.cdnUrl;
|
|
4411
|
-
} catch {
|
|
4412
|
-
return void 0;
|
|
4413
|
-
}
|
|
4414
|
-
}
|
|
4415
|
-
/**
|
|
4416
|
-
* Get peer dependencies for a package.
|
|
4417
|
-
*/
|
|
4418
|
-
getPeerDependencies(packageName) {
|
|
4419
|
-
return getPackagePeerDependencies(packageName, this.registry);
|
|
4420
|
-
}
|
|
4421
|
-
/**
|
|
4422
|
-
* Create the current registry (default + custom).
|
|
4423
|
-
*/
|
|
4424
|
-
getRegistry() {
|
|
4425
|
-
return this.registry;
|
|
4426
|
-
}
|
|
4427
|
-
/**
|
|
4428
|
-
* Get the current platform.
|
|
4429
|
-
*/
|
|
4430
|
-
getPlatform() {
|
|
4431
|
-
return this.options.platform;
|
|
4432
|
-
}
|
|
4433
|
-
/**
|
|
4434
|
-
* Create a resolved dependency object.
|
|
4435
|
-
*/
|
|
4436
|
-
createResolvedDependency(packageName, config, provider, version) {
|
|
4437
|
-
return {
|
|
4438
|
-
packageName,
|
|
4439
|
-
version: version ?? this.extractVersionFromUrl(config.url) ?? "latest",
|
|
4440
|
-
cdnUrl: config.url,
|
|
4441
|
-
integrity: config.integrity,
|
|
4442
|
-
global: config.global,
|
|
4443
|
-
esm: config.esm ?? false,
|
|
4444
|
-
provider
|
|
4445
2954
|
};
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
if (versionMatch2) {
|
|
4457
|
-
return versionMatch2[1];
|
|
4458
|
-
}
|
|
4459
|
-
return void 0;
|
|
4460
|
-
}
|
|
4461
|
-
};
|
|
2955
|
+
const outputPlaceholder = options?.placeholder ?? HYBRID_DATA_PLACEHOLDER;
|
|
2956
|
+
const inputPlaceholder = options?.inputPlaceholder ?? HYBRID_INPUT_PLACEHOLDER;
|
|
2957
|
+
return `
|
|
2958
|
+
<!-- Tool Data Injection (Hybrid Mode - Replace placeholders with JSON) -->
|
|
2959
|
+
<script>
|
|
2960
|
+
window.__mcpToolName = ${safeJson(toolName)};
|
|
2961
|
+
window.__mcpToolInput = "${inputPlaceholder}";
|
|
2962
|
+
window.__mcpToolOutput = "${outputPlaceholder}";
|
|
2963
|
+
window.__mcpStructuredContent = ${safeJson(structuredContent ?? null)};
|
|
2964
|
+
window.__mcpHybridError = null;
|
|
4462
2965
|
|
|
4463
|
-
//
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
platform = "unknown",
|
|
4482
|
-
skipCache = false,
|
|
4483
|
-
ssr = false,
|
|
4484
|
-
ssrContext = {},
|
|
4485
|
-
executeCode: executeCode3
|
|
4486
|
-
} = options;
|
|
4487
|
-
const absoluteEntryPath = (0, import_path3.resolve)(entryPath);
|
|
4488
|
-
if (!(0, import_fs3.existsSync)(absoluteEntryPath)) {
|
|
4489
|
-
throw new Error(`Entry file not found: ${absoluteEntryPath}`);
|
|
4490
|
-
}
|
|
4491
|
-
const hashResult = await calculateComponentHash({
|
|
4492
|
-
entryPath: absoluteEntryPath,
|
|
4493
|
-
externals,
|
|
4494
|
-
dependencies,
|
|
4495
|
-
bundleOptions
|
|
4496
|
-
});
|
|
4497
|
-
if (!skipCache) {
|
|
4498
|
-
const cached = await this.storage.get(hashResult.hash);
|
|
4499
|
-
if (cached) {
|
|
4500
|
-
return {
|
|
4501
|
-
manifest: cached,
|
|
4502
|
-
cached: true,
|
|
4503
|
-
buildTimeMs: performance.now() - startTime
|
|
4504
|
-
};
|
|
4505
|
-
}
|
|
4506
|
-
}
|
|
4507
|
-
const source = await (0, import_promises3.readFile)(absoluteEntryPath, "utf8");
|
|
4508
|
-
const resolver = new DependencyResolver({ platform });
|
|
4509
|
-
const resolvedDeps = [];
|
|
4510
|
-
for (const pkg of externals) {
|
|
4511
|
-
try {
|
|
4512
|
-
const override = dependencies[pkg];
|
|
4513
|
-
const resolved = resolver.resolve(pkg, override);
|
|
4514
|
-
if (resolved) {
|
|
4515
|
-
resolvedDeps.push(resolved);
|
|
2966
|
+
// Parse placeholders if they've been replaced with actual JSON
|
|
2967
|
+
(function() {
|
|
2968
|
+
var outputNotReplaced = false;
|
|
2969
|
+
|
|
2970
|
+
// Parse output placeholder
|
|
2971
|
+
var rawOutput = window.__mcpToolOutput;
|
|
2972
|
+
if (typeof rawOutput === 'string' && rawOutput !== "${outputPlaceholder}") {
|
|
2973
|
+
try {
|
|
2974
|
+
window.__mcpToolOutput = JSON.parse(rawOutput);
|
|
2975
|
+
} catch (e) {
|
|
2976
|
+
console.warn('[FrontMCP] Failed to parse injected output data:', e);
|
|
2977
|
+
window.__mcpToolOutput = null;
|
|
2978
|
+
window.__mcpHybridError = 'Failed to parse output data';
|
|
2979
|
+
}
|
|
2980
|
+
} else if (rawOutput === "${outputPlaceholder}") {
|
|
2981
|
+
// Placeholder not replaced - no data was injected
|
|
2982
|
+
window.__mcpToolOutput = null;
|
|
2983
|
+
outputNotReplaced = true;
|
|
4516
2984
|
}
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
if (providerConfig?.peerDependencies) {
|
|
4527
|
-
for (const peer of providerConfig.peerDependencies) {
|
|
4528
|
-
if (!allExternals.has(peer)) {
|
|
4529
|
-
allExternals.add(peer);
|
|
4530
|
-
try {
|
|
4531
|
-
const peerOverride = dependencies[peer];
|
|
4532
|
-
const resolved = resolver.resolve(peer, peerOverride);
|
|
4533
|
-
if (resolved) {
|
|
4534
|
-
resolvedDeps.push(resolved);
|
|
4535
|
-
}
|
|
4536
|
-
} catch {
|
|
4537
|
-
}
|
|
4538
|
-
}
|
|
2985
|
+
|
|
2986
|
+
// Parse input placeholder
|
|
2987
|
+
var rawInput = window.__mcpToolInput;
|
|
2988
|
+
if (typeof rawInput === 'string' && rawInput !== "${inputPlaceholder}") {
|
|
2989
|
+
try {
|
|
2990
|
+
window.__mcpToolInput = JSON.parse(rawInput);
|
|
2991
|
+
} catch (e) {
|
|
2992
|
+
console.warn('[FrontMCP] Failed to parse injected input data:', e);
|
|
2993
|
+
window.__mcpToolInput = null;
|
|
4539
2994
|
}
|
|
2995
|
+
} else if (rawInput === "${inputPlaceholder}") {
|
|
2996
|
+
window.__mcpToolInput = null;
|
|
4540
2997
|
}
|
|
2998
|
+
|
|
2999
|
+
// Set error if output placeholder was not replaced (no data provided)
|
|
3000
|
+
if (outputNotReplaced) {
|
|
3001
|
+
window.__mcpHybridError = 'No data provided. The output placeholder was not replaced.';
|
|
3002
|
+
}
|
|
3003
|
+
})();
|
|
3004
|
+
|
|
3005
|
+
// Initialize FrontMCP context with appropriate loading/error state
|
|
3006
|
+
if (window.__frontmcp && window.__frontmcp.setContext) {
|
|
3007
|
+
window.__frontmcp.setContext({
|
|
3008
|
+
toolName: window.__mcpToolName,
|
|
3009
|
+
toolInput: window.__mcpToolInput,
|
|
3010
|
+
toolOutput: window.__mcpToolOutput,
|
|
3011
|
+
structuredContent: window.__mcpStructuredContent,
|
|
3012
|
+
loading: false,
|
|
3013
|
+
error: window.__mcpHybridError,
|
|
3014
|
+
});
|
|
4541
3015
|
}
|
|
4542
|
-
|
|
4543
|
-
const importMap = createImportMap(resolvedDeps);
|
|
4544
|
-
const bundleResult = await this.bundleComponent({
|
|
4545
|
-
source,
|
|
4546
|
-
entryPath: absoluteEntryPath,
|
|
4547
|
-
externals: Array.from(allExternals),
|
|
4548
|
-
bundleOptions
|
|
4549
|
-
});
|
|
4550
|
-
let ssrHtml;
|
|
4551
|
-
if (ssr) {
|
|
4552
|
-
ssrHtml = await this.renderSSR(bundleResult.code, ssrContext, resolvedDeps, executeCode3);
|
|
4553
|
-
}
|
|
4554
|
-
const manifest = {
|
|
4555
|
-
version: "1.0",
|
|
4556
|
-
buildId: (0, import_crypto3.randomUUID)(),
|
|
4557
|
-
toolName,
|
|
4558
|
-
entryPath: absoluteEntryPath,
|
|
4559
|
-
contentHash: hashResult.hash,
|
|
4560
|
-
dependencies: resolvedDeps,
|
|
4561
|
-
outputs: {
|
|
4562
|
-
code: bundleResult.code,
|
|
4563
|
-
sourceMap: bundleResult.map,
|
|
4564
|
-
ssrHtml
|
|
4565
|
-
},
|
|
4566
|
-
importMap,
|
|
4567
|
-
metadata: {
|
|
4568
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4569
|
-
buildTimeMs: performance.now() - startTime,
|
|
4570
|
-
totalSize: Buffer.byteLength(bundleResult.code, "utf8"),
|
|
4571
|
-
bundlerVersion: bundleResult.bundlerVersion
|
|
4572
|
-
}
|
|
4573
|
-
};
|
|
4574
|
-
await this.storage.set(hashResult.hash, manifest);
|
|
4575
|
-
return {
|
|
4576
|
-
manifest,
|
|
4577
|
-
cached: false,
|
|
4578
|
-
buildTimeMs: performance.now() - startTime
|
|
4579
|
-
};
|
|
4580
|
-
}
|
|
4581
|
-
/**
|
|
4582
|
-
* Build multiple components.
|
|
4583
|
-
*/
|
|
4584
|
-
async buildMany(options) {
|
|
4585
|
-
return Promise.all(options.map((opt) => this.build(opt)));
|
|
4586
|
-
}
|
|
4587
|
-
/**
|
|
4588
|
-
* Check if a component needs rebuilding.
|
|
4589
|
-
*/
|
|
4590
|
-
async needsRebuild(options) {
|
|
4591
|
-
const absoluteEntryPath = (0, import_path3.resolve)(options.entryPath);
|
|
4592
|
-
const hashResult = await calculateComponentHash({
|
|
4593
|
-
entryPath: absoluteEntryPath,
|
|
4594
|
-
externals: options.externals,
|
|
4595
|
-
dependencies: options.dependencies,
|
|
4596
|
-
bundleOptions: options.bundleOptions
|
|
4597
|
-
});
|
|
4598
|
-
const cached = await this.storage.has(hashResult.hash);
|
|
4599
|
-
return !cached;
|
|
4600
|
-
}
|
|
4601
|
-
/**
|
|
4602
|
-
* Get a cached build if it exists.
|
|
4603
|
-
*/
|
|
4604
|
-
async getCached(options) {
|
|
4605
|
-
const absoluteEntryPath = (0, import_path3.resolve)(options.entryPath);
|
|
4606
|
-
const hashResult = await calculateComponentHash({
|
|
4607
|
-
entryPath: absoluteEntryPath,
|
|
4608
|
-
externals: options.externals,
|
|
4609
|
-
dependencies: options.dependencies,
|
|
4610
|
-
bundleOptions: options.bundleOptions
|
|
4611
|
-
});
|
|
4612
|
-
return this.storage.get(hashResult.hash);
|
|
4613
|
-
}
|
|
4614
|
-
/**
|
|
4615
|
-
* Invalidate a cached build.
|
|
4616
|
-
*/
|
|
4617
|
-
async invalidate(contentHash) {
|
|
4618
|
-
return this.storage.delete(contentHash);
|
|
4619
|
-
}
|
|
4620
|
-
/**
|
|
4621
|
-
* Generate complete HTML for a built component.
|
|
4622
|
-
*/
|
|
4623
|
-
generateHTML(manifest, minify = false) {
|
|
4624
|
-
const parts = [];
|
|
4625
|
-
const dependencyHtml = generateDependencyHTML(manifest.dependencies, { minify });
|
|
4626
|
-
parts.push(dependencyHtml);
|
|
4627
|
-
parts.push(`<script type="module">${manifest.outputs.code}</script>`);
|
|
4628
|
-
return parts.join(minify ? "" : "\n");
|
|
3016
|
+
</script>`;
|
|
4629
3017
|
}
|
|
4630
3018
|
/**
|
|
4631
|
-
*
|
|
3019
|
+
* Build component render script.
|
|
3020
|
+
* Wraps CommonJS code with module/exports shim to capture the component.
|
|
4632
3021
|
*/
|
|
4633
|
-
|
|
4634
|
-
const
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
3022
|
+
buildComponentRenderScript(componentCode, rootId, cdnType) {
|
|
3023
|
+
const wrappedCode = `
|
|
3024
|
+
// CommonJS module shim
|
|
3025
|
+
var module = { exports: {} };
|
|
3026
|
+
var exports = module.exports;
|
|
3027
|
+
|
|
3028
|
+
// Execute transpiled component code (CommonJS format)
|
|
3029
|
+
${componentCode}
|
|
3030
|
+
|
|
3031
|
+
// Capture the component export
|
|
3032
|
+
window.__frontmcp_component = module.exports;
|
|
3033
|
+
`;
|
|
3034
|
+
if (cdnType === "umd") {
|
|
3035
|
+
return `
|
|
3036
|
+
<!-- Component Render Script (UMD - synchronous) -->
|
|
3037
|
+
<script>
|
|
3038
|
+
(function() {
|
|
3039
|
+
${wrappedCode}
|
|
3040
|
+
|
|
3041
|
+
// Get the component
|
|
3042
|
+
var Component = window.__frontmcp_component.default || window.__frontmcp_component;
|
|
3043
|
+
|
|
3044
|
+
// Render the component
|
|
3045
|
+
var container = document.getElementById('${rootId}');
|
|
3046
|
+
if (container && window.ReactDOM && window.ReactDOM.createRoot) {
|
|
3047
|
+
var root = window.ReactDOM.createRoot(container);
|
|
3048
|
+
root.render(React.createElement(Component, {
|
|
3049
|
+
output: window.__mcpToolOutput,
|
|
3050
|
+
input: window.__mcpToolInput,
|
|
3051
|
+
}));
|
|
3052
|
+
} else if (container && window.ReactDOM && window.ReactDOM.render) {
|
|
3053
|
+
// Fallback for React 17
|
|
3054
|
+
window.ReactDOM.render(
|
|
3055
|
+
React.createElement(Component, {
|
|
3056
|
+
output: window.__mcpToolOutput,
|
|
3057
|
+
input: window.__mcpToolInput,
|
|
3058
|
+
}),
|
|
3059
|
+
container
|
|
3060
|
+
);
|
|
3061
|
+
}
|
|
3062
|
+
})();
|
|
3063
|
+
</script>`;
|
|
3064
|
+
} else {
|
|
3065
|
+
return `
|
|
3066
|
+
<!-- Component Render Script (ESM - waits for React) -->
|
|
3067
|
+
<script type="module">
|
|
3068
|
+
function renderComponent() {
|
|
3069
|
+
${wrappedCode}
|
|
3070
|
+
|
|
3071
|
+
// Get the component
|
|
3072
|
+
var Component = window.__frontmcp_component.default || window.__frontmcp_component;
|
|
3073
|
+
|
|
3074
|
+
// Render the component
|
|
3075
|
+
var container = document.getElementById('${rootId}');
|
|
3076
|
+
if (container && window.ReactDOM && window.ReactDOM.createRoot) {
|
|
3077
|
+
var root = window.ReactDOM.createRoot(container);
|
|
3078
|
+
root.render(React.createElement(Component, {
|
|
3079
|
+
output: window.__mcpToolOutput,
|
|
3080
|
+
input: window.__mcpToolInput,
|
|
3081
|
+
}));
|
|
3082
|
+
}
|
|
4640
3083
|
}
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
sourcemap: bundleOptions.sourceMaps ? "inline" : false,
|
|
4650
|
-
target: bundleOptions.target ?? "es2020",
|
|
4651
|
-
treeShaking: bundleOptions.treeShake ?? true,
|
|
4652
|
-
jsx: "automatic",
|
|
4653
|
-
jsxImportSource: bundleOptions.jsxImportSource ?? "react",
|
|
4654
|
-
// Mark externals for later import map resolution
|
|
4655
|
-
banner: externals.length > 0 ? `/* externals: ${externals.join(", ")} */` : void 0
|
|
4656
|
-
});
|
|
4657
|
-
return {
|
|
4658
|
-
code: result.code,
|
|
4659
|
-
map: result.map || void 0,
|
|
4660
|
-
bundlerVersion: this.esbuild.version
|
|
4661
|
-
};
|
|
4662
|
-
} catch (error) {
|
|
4663
|
-
throw new Error(`Bundle failed for ${entryPath}: ${error}`);
|
|
3084
|
+
|
|
3085
|
+
// Wait for React to be ready
|
|
3086
|
+
if (window.__reactReady) {
|
|
3087
|
+
renderComponent();
|
|
3088
|
+
} else {
|
|
3089
|
+
window.addEventListener('react:ready', renderComponent);
|
|
3090
|
+
}
|
|
3091
|
+
</script>`;
|
|
4664
3092
|
}
|
|
4665
3093
|
}
|
|
4666
3094
|
/**
|
|
4667
|
-
*
|
|
3095
|
+
* Assemble the complete static HTML document.
|
|
4668
3096
|
*/
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
}
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
const Component = module2.exports.default || module2.exports;
|
|
4687
|
-
if (typeof Component !== "function") {
|
|
4688
|
-
console.warn("SSR: No default component export found");
|
|
4689
|
-
return void 0;
|
|
4690
|
-
}
|
|
4691
|
-
const element = React.createElement(Component, context);
|
|
4692
|
-
return ReactDOMServer.renderToString(element);
|
|
4693
|
-
} catch (error) {
|
|
4694
|
-
console.warn(`SSR failed: ${error}`);
|
|
4695
|
-
return void 0;
|
|
4696
|
-
}
|
|
3097
|
+
assembleStaticHTML(parts) {
|
|
3098
|
+
return `<!DOCTYPE html>
|
|
3099
|
+
<html lang="en">
|
|
3100
|
+
<head>
|
|
3101
|
+
<title>${(0, import_utils.escapeHtml)(parts.title)}</title>
|
|
3102
|
+
${parts.head}
|
|
3103
|
+
${parts.reactRuntime}
|
|
3104
|
+
${parts.frontmcpRuntime}
|
|
3105
|
+
${parts.dataScript}
|
|
3106
|
+
</head>
|
|
3107
|
+
<body>
|
|
3108
|
+
<div id="${parts.rootId}" class="frontmcp-loading">
|
|
3109
|
+
<div class="frontmcp-spinner"></div>
|
|
3110
|
+
</div>
|
|
3111
|
+
${parts.componentScript}
|
|
3112
|
+
</body>
|
|
3113
|
+
</html>`;
|
|
4697
3114
|
}
|
|
4698
3115
|
};
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
const storage = new FilesystemStorage2({ cacheDir });
|
|
4702
|
-
await storage.initialize();
|
|
4703
|
-
return new ComponentBuilder(storage);
|
|
4704
|
-
}
|
|
4705
|
-
async function createRedisBuilder(redisClient, keyPrefix = "frontmcp:ui:build:") {
|
|
4706
|
-
const { RedisStorage: RedisStorage2 } = await Promise.resolve().then(() => (init_redis(), redis_exports));
|
|
4707
|
-
const storage = new RedisStorage2({
|
|
4708
|
-
client: redisClient,
|
|
4709
|
-
keyPrefix
|
|
4710
|
-
});
|
|
4711
|
-
await storage.initialize();
|
|
4712
|
-
return new ComponentBuilder(storage);
|
|
3116
|
+
function createBundler(options) {
|
|
3117
|
+
return new InMemoryBundler(options);
|
|
4713
3118
|
}
|
|
3119
|
+
|
|
3120
|
+
// libs/ui/src/bundler/index.ts
|
|
3121
|
+
var import_bundler4 = require("@frontmcp/uipack/bundler");
|
|
3122
|
+
var import_bundler5 = require("@frontmcp/uipack/bundler");
|
|
3123
|
+
var import_bundler6 = require("@frontmcp/uipack/bundler");
|
|
3124
|
+
var import_bundler7 = require("@frontmcp/uipack/bundler");
|
|
4714
3125
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4715
3126
|
0 && (module.exports = {
|
|
3127
|
+
ALL_PLATFORMS,
|
|
4716
3128
|
BundlerCache,
|
|
4717
3129
|
ComponentBuilder,
|
|
4718
3130
|
DEFAULT_BUNDLER_OPTIONS,
|
|
@@ -4722,6 +3134,8 @@ async function createRedisBuilder(redisClient, keyPrefix = "frontmcp:ui:build:")
|
|
|
4722
3134
|
DEFAULT_STORAGE_OPTIONS,
|
|
4723
3135
|
ExecutionError,
|
|
4724
3136
|
FilesystemStorage,
|
|
3137
|
+
HYBRID_DATA_PLACEHOLDER,
|
|
3138
|
+
HYBRID_INPUT_PLACEHOLDER,
|
|
4725
3139
|
InMemoryBundler,
|
|
4726
3140
|
RedisStorage,
|
|
4727
3141
|
STATIC_HTML_CDN,
|