@frontmcp/uipack 0.6.1
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/CLAUDE.md +246 -0
- package/LICENSE +201 -0
- package/README.md +150 -0
- package/adapters/index.d.ts +13 -0
- package/adapters/index.d.ts.map +1 -0
- package/adapters/index.js +462 -0
- package/adapters/platform-meta.d.ts +166 -0
- package/adapters/platform-meta.d.ts.map +1 -0
- package/adapters/response-builder.d.ts +108 -0
- package/adapters/response-builder.d.ts.map +1 -0
- package/adapters/serving-mode.d.ts +107 -0
- package/adapters/serving-mode.d.ts.map +1 -0
- package/base-template/bridge.d.ts +90 -0
- package/base-template/bridge.d.ts.map +1 -0
- package/base-template/default-base-template.d.ts +92 -0
- package/base-template/default-base-template.d.ts.map +1 -0
- package/base-template/index.d.ts +15 -0
- package/base-template/index.d.ts.map +1 -0
- package/base-template/index.js +1398 -0
- package/base-template/polyfills.d.ts +31 -0
- package/base-template/polyfills.d.ts.map +1 -0
- package/base-template/theme-styles.d.ts +74 -0
- package/base-template/theme-styles.d.ts.map +1 -0
- package/bridge-runtime/iife-generator.d.ts +62 -0
- package/bridge-runtime/iife-generator.d.ts.map +1 -0
- package/bridge-runtime/index.d.ts +10 -0
- package/bridge-runtime/index.d.ts.map +1 -0
- package/bridge-runtime/index.js +883 -0
- package/build/cdn-resources.d.ts +243 -0
- package/build/cdn-resources.d.ts.map +1 -0
- package/build/index.d.ts +295 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +6861 -0
- package/build/widget-manifest.d.ts +362 -0
- package/build/widget-manifest.d.ts.map +1 -0
- package/bundler/cache.d.ts +173 -0
- package/bundler/cache.d.ts.map +1 -0
- package/bundler/file-cache/component-builder.d.ts +167 -0
- package/bundler/file-cache/component-builder.d.ts.map +1 -0
- package/bundler/file-cache/hash-calculator.d.ts +155 -0
- package/bundler/file-cache/hash-calculator.d.ts.map +1 -0
- package/bundler/file-cache/index.d.ts +12 -0
- package/bundler/file-cache/index.d.ts.map +1 -0
- package/bundler/file-cache/storage/filesystem.d.ts +149 -0
- package/bundler/file-cache/storage/filesystem.d.ts.map +1 -0
- package/bundler/file-cache/storage/index.d.ts +11 -0
- package/bundler/file-cache/storage/index.d.ts.map +1 -0
- package/bundler/file-cache/storage/interface.d.ts +152 -0
- package/bundler/file-cache/storage/interface.d.ts.map +1 -0
- package/bundler/file-cache/storage/redis.d.ts +139 -0
- package/bundler/file-cache/storage/redis.d.ts.map +1 -0
- package/bundler/index.d.ts +35 -0
- package/bundler/index.d.ts.map +1 -0
- package/bundler/index.js +2947 -0
- package/bundler/sandbox/enclave-adapter.d.ts +121 -0
- package/bundler/sandbox/enclave-adapter.d.ts.map +1 -0
- package/bundler/sandbox/executor.d.ts +14 -0
- package/bundler/sandbox/executor.d.ts.map +1 -0
- package/bundler/sandbox/policy.d.ts +62 -0
- package/bundler/sandbox/policy.d.ts.map +1 -0
- package/bundler/types.d.ts +702 -0
- package/bundler/types.d.ts.map +1 -0
- package/dependency/cdn-registry.d.ts +98 -0
- package/dependency/cdn-registry.d.ts.map +1 -0
- package/dependency/import-map.d.ts +186 -0
- package/dependency/import-map.d.ts.map +1 -0
- package/dependency/import-parser.d.ts +82 -0
- package/dependency/import-parser.d.ts.map +1 -0
- package/dependency/index.d.ts +17 -0
- package/dependency/index.d.ts.map +1 -0
- package/dependency/index.js +3215 -0
- package/dependency/resolver.d.ts +164 -0
- package/dependency/resolver.d.ts.map +1 -0
- package/dependency/schemas.d.ts +486 -0
- package/dependency/schemas.d.ts.map +1 -0
- package/dependency/template-loader.d.ts +204 -0
- package/dependency/template-loader.d.ts.map +1 -0
- package/dependency/template-processor.d.ts +118 -0
- package/dependency/template-processor.d.ts.map +1 -0
- package/dependency/types.d.ts +739 -0
- package/dependency/types.d.ts.map +1 -0
- package/esm/adapters/index.d.ts +13 -0
- package/esm/adapters/index.d.ts.map +1 -0
- package/esm/adapters/index.js +427 -0
- package/esm/adapters/platform-meta.d.ts +166 -0
- package/esm/adapters/platform-meta.d.ts.map +1 -0
- package/esm/adapters/response-builder.d.ts +108 -0
- package/esm/adapters/response-builder.d.ts.map +1 -0
- package/esm/adapters/serving-mode.d.ts +107 -0
- package/esm/adapters/serving-mode.d.ts.map +1 -0
- package/esm/base-template/bridge.d.ts +90 -0
- package/esm/base-template/bridge.d.ts.map +1 -0
- package/esm/base-template/default-base-template.d.ts +92 -0
- package/esm/base-template/default-base-template.d.ts.map +1 -0
- package/esm/base-template/index.d.ts +15 -0
- package/esm/base-template/index.d.ts.map +1 -0
- package/esm/base-template/index.js +1364 -0
- package/esm/base-template/polyfills.d.ts +31 -0
- package/esm/base-template/polyfills.d.ts.map +1 -0
- package/esm/base-template/theme-styles.d.ts +74 -0
- package/esm/base-template/theme-styles.d.ts.map +1 -0
- package/esm/bridge-runtime/iife-generator.d.ts +62 -0
- package/esm/bridge-runtime/iife-generator.d.ts.map +1 -0
- package/esm/bridge-runtime/index.d.ts +10 -0
- package/esm/bridge-runtime/index.d.ts.map +1 -0
- package/esm/bridge-runtime/index.js +853 -0
- package/esm/build/cdn-resources.d.ts +243 -0
- package/esm/build/cdn-resources.d.ts.map +1 -0
- package/esm/build/index.d.ts +295 -0
- package/esm/build/index.d.ts.map +1 -0
- package/esm/build/index.js +6786 -0
- package/esm/build/widget-manifest.d.ts +362 -0
- package/esm/build/widget-manifest.d.ts.map +1 -0
- package/esm/bundler/cache.d.ts +173 -0
- package/esm/bundler/cache.d.ts.map +1 -0
- package/esm/bundler/file-cache/component-builder.d.ts +167 -0
- package/esm/bundler/file-cache/component-builder.d.ts.map +1 -0
- package/esm/bundler/file-cache/hash-calculator.d.ts +155 -0
- package/esm/bundler/file-cache/hash-calculator.d.ts.map +1 -0
- package/esm/bundler/file-cache/index.d.ts +12 -0
- package/esm/bundler/file-cache/index.d.ts.map +1 -0
- package/esm/bundler/file-cache/storage/filesystem.d.ts +149 -0
- package/esm/bundler/file-cache/storage/filesystem.d.ts.map +1 -0
- package/esm/bundler/file-cache/storage/index.d.ts +11 -0
- package/esm/bundler/file-cache/storage/index.d.ts.map +1 -0
- package/esm/bundler/file-cache/storage/interface.d.ts +152 -0
- package/esm/bundler/file-cache/storage/interface.d.ts.map +1 -0
- package/esm/bundler/file-cache/storage/redis.d.ts +139 -0
- package/esm/bundler/file-cache/storage/redis.d.ts.map +1 -0
- package/esm/bundler/index.d.ts +35 -0
- package/esm/bundler/index.d.ts.map +1 -0
- package/esm/bundler/index.js +2882 -0
- package/esm/bundler/sandbox/enclave-adapter.d.ts +121 -0
- package/esm/bundler/sandbox/enclave-adapter.d.ts.map +1 -0
- package/esm/bundler/sandbox/executor.d.ts +14 -0
- package/esm/bundler/sandbox/executor.d.ts.map +1 -0
- package/esm/bundler/sandbox/policy.d.ts +62 -0
- package/esm/bundler/sandbox/policy.d.ts.map +1 -0
- package/esm/bundler/types.d.ts +702 -0
- package/esm/bundler/types.d.ts.map +1 -0
- package/esm/dependency/cdn-registry.d.ts +98 -0
- package/esm/dependency/cdn-registry.d.ts.map +1 -0
- package/esm/dependency/import-map.d.ts +186 -0
- package/esm/dependency/import-map.d.ts.map +1 -0
- package/esm/dependency/import-parser.d.ts +82 -0
- package/esm/dependency/import-parser.d.ts.map +1 -0
- package/esm/dependency/index.d.ts +17 -0
- package/esm/dependency/index.d.ts.map +1 -0
- package/esm/dependency/index.js +3096 -0
- package/esm/dependency/resolver.d.ts +164 -0
- package/esm/dependency/resolver.d.ts.map +1 -0
- package/esm/dependency/schemas.d.ts +486 -0
- package/esm/dependency/schemas.d.ts.map +1 -0
- package/esm/dependency/template-loader.d.ts +204 -0
- package/esm/dependency/template-loader.d.ts.map +1 -0
- package/esm/dependency/template-processor.d.ts +118 -0
- package/esm/dependency/template-processor.d.ts.map +1 -0
- package/esm/dependency/types.d.ts +739 -0
- package/esm/dependency/types.d.ts.map +1 -0
- package/esm/handlebars/expression-extractor.d.ts +147 -0
- package/esm/handlebars/expression-extractor.d.ts.map +1 -0
- package/esm/handlebars/helpers.d.ts +339 -0
- package/esm/handlebars/helpers.d.ts.map +1 -0
- package/esm/handlebars/index.d.ts +195 -0
- package/esm/handlebars/index.d.ts.map +1 -0
- package/esm/handlebars/index.js +587 -0
- package/esm/index.d.ts +50 -0
- package/esm/index.d.ts.map +1 -0
- package/esm/index.js +12434 -0
- package/esm/package.json +68 -0
- package/esm/registry/index.d.ts +46 -0
- package/esm/registry/index.d.ts.map +1 -0
- package/esm/registry/index.js +6237 -0
- package/esm/registry/render-template.d.ts +91 -0
- package/esm/registry/render-template.d.ts.map +1 -0
- package/esm/registry/tool-ui.registry.d.ts +294 -0
- package/esm/registry/tool-ui.registry.d.ts.map +1 -0
- package/esm/registry/uri-utils.d.ts +56 -0
- package/esm/registry/uri-utils.d.ts.map +1 -0
- package/esm/renderers/cache.d.ts +145 -0
- package/esm/renderers/cache.d.ts.map +1 -0
- package/esm/renderers/html.renderer.d.ts +123 -0
- package/esm/renderers/html.renderer.d.ts.map +1 -0
- package/esm/renderers/index.d.ts +36 -0
- package/esm/renderers/index.d.ts.map +1 -0
- package/esm/renderers/index.js +1654 -0
- package/esm/renderers/mdx.renderer.d.ts +120 -0
- package/esm/renderers/mdx.renderer.d.ts.map +1 -0
- package/esm/renderers/registry.d.ts +133 -0
- package/esm/renderers/registry.d.ts.map +1 -0
- package/esm/renderers/types.d.ts +342 -0
- package/esm/renderers/types.d.ts.map +1 -0
- package/esm/renderers/utils/detect.d.ts +107 -0
- package/esm/renderers/utils/detect.d.ts.map +1 -0
- package/esm/renderers/utils/hash.d.ts +40 -0
- package/esm/renderers/utils/hash.d.ts.map +1 -0
- package/esm/renderers/utils/index.d.ts +9 -0
- package/esm/renderers/utils/index.d.ts.map +1 -0
- package/esm/renderers/utils/transpiler.d.ts +89 -0
- package/esm/renderers/utils/transpiler.d.ts.map +1 -0
- package/esm/runtime/adapters/html.adapter.d.ts +59 -0
- package/esm/runtime/adapters/html.adapter.d.ts.map +1 -0
- package/esm/runtime/adapters/index.d.ts +26 -0
- package/esm/runtime/adapters/index.d.ts.map +1 -0
- package/esm/runtime/adapters/mdx.adapter.d.ts +73 -0
- package/esm/runtime/adapters/mdx.adapter.d.ts.map +1 -0
- package/esm/runtime/adapters/types.d.ts +95 -0
- package/esm/runtime/adapters/types.d.ts.map +1 -0
- package/esm/runtime/csp.d.ts +48 -0
- package/esm/runtime/csp.d.ts.map +1 -0
- package/esm/runtime/index.d.ts +17 -0
- package/esm/runtime/index.d.ts.map +1 -0
- package/esm/runtime/index.js +4976 -0
- package/esm/runtime/mcp-bridge.d.ts +101 -0
- package/esm/runtime/mcp-bridge.d.ts.map +1 -0
- package/esm/runtime/renderer-runtime.d.ts +133 -0
- package/esm/runtime/renderer-runtime.d.ts.map +1 -0
- package/esm/runtime/sanitizer.d.ts +172 -0
- package/esm/runtime/sanitizer.d.ts.map +1 -0
- package/esm/runtime/types.d.ts +415 -0
- package/esm/runtime/types.d.ts.map +1 -0
- package/esm/runtime/wrapper.d.ts +421 -0
- package/esm/runtime/wrapper.d.ts.map +1 -0
- package/esm/styles/index.d.ts +8 -0
- package/esm/styles/index.d.ts.map +1 -0
- package/esm/styles/index.js +171 -0
- package/esm/styles/variants.d.ts +51 -0
- package/esm/styles/variants.d.ts.map +1 -0
- package/esm/theme/cdn.d.ts +195 -0
- package/esm/theme/cdn.d.ts.map +1 -0
- package/esm/theme/index.d.ts +18 -0
- package/esm/theme/index.d.ts.map +1 -0
- package/esm/theme/index.js +700 -0
- package/esm/theme/platforms.d.ts +107 -0
- package/esm/theme/platforms.d.ts.map +1 -0
- package/esm/theme/presets/github-openai.d.ts +50 -0
- package/esm/theme/presets/github-openai.d.ts.map +1 -0
- package/esm/theme/presets/index.d.ts +11 -0
- package/esm/theme/presets/index.d.ts.map +1 -0
- package/esm/theme/theme.d.ts +396 -0
- package/esm/theme/theme.d.ts.map +1 -0
- package/esm/tool-template/builder.d.ts +213 -0
- package/esm/tool-template/builder.d.ts.map +1 -0
- package/esm/tool-template/index.d.ts +16 -0
- package/esm/tool-template/index.d.ts.map +1 -0
- package/esm/tool-template/index.js +3518 -0
- package/esm/types/index.d.ts +14 -0
- package/esm/types/index.d.ts.map +1 -0
- package/esm/types/index.js +75 -0
- package/esm/types/ui-config.d.ts +641 -0
- package/esm/types/ui-config.d.ts.map +1 -0
- package/esm/types/ui-runtime.d.ts +1008 -0
- package/esm/types/ui-runtime.d.ts.map +1 -0
- package/esm/typings/cache/cache-adapter.d.ts +125 -0
- package/esm/typings/cache/cache-adapter.d.ts.map +1 -0
- package/esm/typings/cache/index.d.ts +10 -0
- package/esm/typings/cache/index.d.ts.map +1 -0
- package/esm/typings/cache/memory-cache.d.ts +92 -0
- package/esm/typings/cache/memory-cache.d.ts.map +1 -0
- package/esm/typings/dts-parser.d.ts +90 -0
- package/esm/typings/dts-parser.d.ts.map +1 -0
- package/esm/typings/index.d.ts +48 -0
- package/esm/typings/index.d.ts.map +1 -0
- package/esm/typings/index.js +812 -0
- package/esm/typings/schemas.d.ts +232 -0
- package/esm/typings/schemas.d.ts.map +1 -0
- package/esm/typings/type-fetcher.d.ts +89 -0
- package/esm/typings/type-fetcher.d.ts.map +1 -0
- package/esm/typings/types.d.ts +320 -0
- package/esm/typings/types.d.ts.map +1 -0
- package/esm/utils/escape-html.d.ts +58 -0
- package/esm/utils/escape-html.d.ts.map +1 -0
- package/esm/utils/index.d.ts +10 -0
- package/esm/utils/index.d.ts.map +1 -0
- package/esm/utils/index.js +40 -0
- package/esm/utils/safe-stringify.d.ts +30 -0
- package/esm/utils/safe-stringify.d.ts.map +1 -0
- package/esm/validation/error-box.d.ts +56 -0
- package/esm/validation/error-box.d.ts.map +1 -0
- package/esm/validation/index.d.ts +13 -0
- package/esm/validation/index.d.ts.map +1 -0
- package/esm/validation/index.js +542 -0
- package/esm/validation/schema-paths.d.ts +118 -0
- package/esm/validation/schema-paths.d.ts.map +1 -0
- package/esm/validation/template-validator.d.ts +143 -0
- package/esm/validation/template-validator.d.ts.map +1 -0
- package/esm/validation/wrapper.d.ts +97 -0
- package/esm/validation/wrapper.d.ts.map +1 -0
- package/handlebars/expression-extractor.d.ts +147 -0
- package/handlebars/expression-extractor.d.ts.map +1 -0
- package/handlebars/helpers.d.ts +339 -0
- package/handlebars/helpers.d.ts.map +1 -0
- package/handlebars/index.d.ts +195 -0
- package/handlebars/index.d.ts.map +1 -0
- package/handlebars/index.js +666 -0
- package/index.d.ts +50 -0
- package/index.d.ts.map +1 -0
- package/index.js +12683 -0
- package/package.json +66 -0
- package/registry/index.d.ts +46 -0
- package/registry/index.d.ts.map +1 -0
- package/registry/index.js +6280 -0
- package/registry/render-template.d.ts +91 -0
- package/registry/render-template.d.ts.map +1 -0
- package/registry/tool-ui.registry.d.ts +294 -0
- package/registry/tool-ui.registry.d.ts.map +1 -0
- package/registry/uri-utils.d.ts +56 -0
- package/registry/uri-utils.d.ts.map +1 -0
- package/renderers/cache.d.ts +145 -0
- package/renderers/cache.d.ts.map +1 -0
- package/renderers/html.renderer.d.ts +123 -0
- package/renderers/html.renderer.d.ts.map +1 -0
- package/renderers/index.d.ts +36 -0
- package/renderers/index.d.ts.map +1 -0
- package/renderers/index.js +1706 -0
- package/renderers/mdx.renderer.d.ts +120 -0
- package/renderers/mdx.renderer.d.ts.map +1 -0
- package/renderers/registry.d.ts +133 -0
- package/renderers/registry.d.ts.map +1 -0
- package/renderers/types.d.ts +342 -0
- package/renderers/types.d.ts.map +1 -0
- package/renderers/utils/detect.d.ts +107 -0
- package/renderers/utils/detect.d.ts.map +1 -0
- package/renderers/utils/hash.d.ts +40 -0
- package/renderers/utils/hash.d.ts.map +1 -0
- package/renderers/utils/index.d.ts +9 -0
- package/renderers/utils/index.d.ts.map +1 -0
- package/renderers/utils/transpiler.d.ts +89 -0
- package/renderers/utils/transpiler.d.ts.map +1 -0
- package/runtime/adapters/html.adapter.d.ts +59 -0
- package/runtime/adapters/html.adapter.d.ts.map +1 -0
- package/runtime/adapters/index.d.ts +26 -0
- package/runtime/adapters/index.d.ts.map +1 -0
- package/runtime/adapters/mdx.adapter.d.ts +73 -0
- package/runtime/adapters/mdx.adapter.d.ts.map +1 -0
- package/runtime/adapters/types.d.ts +95 -0
- package/runtime/adapters/types.d.ts.map +1 -0
- package/runtime/csp.d.ts +48 -0
- package/runtime/csp.d.ts.map +1 -0
- package/runtime/index.d.ts +17 -0
- package/runtime/index.d.ts.map +1 -0
- package/runtime/index.js +5052 -0
- package/runtime/mcp-bridge.d.ts +101 -0
- package/runtime/mcp-bridge.d.ts.map +1 -0
- package/runtime/renderer-runtime.d.ts +133 -0
- package/runtime/renderer-runtime.d.ts.map +1 -0
- package/runtime/sanitizer.d.ts +172 -0
- package/runtime/sanitizer.d.ts.map +1 -0
- package/runtime/types.d.ts +415 -0
- package/runtime/types.d.ts.map +1 -0
- package/runtime/wrapper.d.ts +421 -0
- package/runtime/wrapper.d.ts.map +1 -0
- package/styles/index.d.ts +8 -0
- package/styles/index.d.ts.map +1 -0
- package/styles/index.js +222 -0
- package/styles/variants.d.ts +51 -0
- package/styles/variants.d.ts.map +1 -0
- package/theme/cdn.d.ts +195 -0
- package/theme/cdn.d.ts.map +1 -0
- package/theme/index.d.ts +18 -0
- package/theme/index.d.ts.map +1 -0
- package/theme/index.js +757 -0
- package/theme/platforms.d.ts +107 -0
- package/theme/platforms.d.ts.map +1 -0
- package/theme/presets/github-openai.d.ts +50 -0
- package/theme/presets/github-openai.d.ts.map +1 -0
- package/theme/presets/index.d.ts +11 -0
- package/theme/presets/index.d.ts.map +1 -0
- package/theme/theme.d.ts +396 -0
- package/theme/theme.d.ts.map +1 -0
- package/tool-template/builder.d.ts +213 -0
- package/tool-template/builder.d.ts.map +1 -0
- package/tool-template/index.d.ts +16 -0
- package/tool-template/index.d.ts.map +1 -0
- package/tool-template/index.js +3562 -0
- package/types/index.d.ts +14 -0
- package/types/index.d.ts.map +1 -0
- package/types/index.js +108 -0
- package/types/ui-config.d.ts +641 -0
- package/types/ui-config.d.ts.map +1 -0
- package/types/ui-runtime.d.ts +1008 -0
- package/types/ui-runtime.d.ts.map +1 -0
- package/typings/cache/cache-adapter.d.ts +125 -0
- package/typings/cache/cache-adapter.d.ts.map +1 -0
- package/typings/cache/index.d.ts +10 -0
- package/typings/cache/index.d.ts.map +1 -0
- package/typings/cache/memory-cache.d.ts +92 -0
- package/typings/cache/memory-cache.d.ts.map +1 -0
- package/typings/dts-parser.d.ts +90 -0
- package/typings/dts-parser.d.ts.map +1 -0
- package/typings/index.d.ts +48 -0
- package/typings/index.d.ts.map +1 -0
- package/typings/index.js +868 -0
- package/typings/schemas.d.ts +232 -0
- package/typings/schemas.d.ts.map +1 -0
- package/typings/type-fetcher.d.ts +89 -0
- package/typings/type-fetcher.d.ts.map +1 -0
- package/typings/types.d.ts +320 -0
- package/typings/types.d.ts.map +1 -0
- package/utils/escape-html.d.ts +58 -0
- package/utils/escape-html.d.ts.map +1 -0
- package/utils/index.d.ts +10 -0
- package/utils/index.d.ts.map +1 -0
- package/utils/index.js +70 -0
- package/utils/safe-stringify.d.ts +30 -0
- package/utils/safe-stringify.d.ts.map +1 -0
- package/validation/error-box.d.ts +56 -0
- package/validation/error-box.d.ts.map +1 -0
- package/validation/index.d.ts +13 -0
- package/validation/index.d.ts.map +1 -0
- package/validation/index.js +583 -0
- package/validation/schema-paths.d.ts +118 -0
- package/validation/schema-paths.d.ts.map +1 -0
- package/validation/template-validator.d.ts +143 -0
- package/validation/template-validator.d.ts.map +1 -0
- package/validation/wrapper.d.ts +97 -0
- package/validation/wrapper.d.ts.map +1 -0
|
@@ -0,0 +1,2882 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __esm = (fn, res) => function __init() {
|
|
4
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
5
|
+
};
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// libs/uipack/src/bundler/file-cache/storage/interface.ts
|
|
12
|
+
function calculateManifestSize(manifest) {
|
|
13
|
+
try {
|
|
14
|
+
return Buffer.byteLength(JSON.stringify(manifest), "utf8");
|
|
15
|
+
} catch {
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
var DEFAULT_STORAGE_OPTIONS;
|
|
20
|
+
var init_interface = __esm({
|
|
21
|
+
"libs/uipack/src/bundler/file-cache/storage/interface.ts"() {
|
|
22
|
+
"use strict";
|
|
23
|
+
DEFAULT_STORAGE_OPTIONS = {
|
|
24
|
+
maxEntries: 1e3,
|
|
25
|
+
maxSize: 100 * 1024 * 1024,
|
|
26
|
+
// 100MB
|
|
27
|
+
defaultTtl: 24 * 60 * 60,
|
|
28
|
+
// 24 hours
|
|
29
|
+
compress: false
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// libs/uipack/src/bundler/file-cache/storage/filesystem.ts
|
|
35
|
+
var filesystem_exports = {};
|
|
36
|
+
__export(filesystem_exports, {
|
|
37
|
+
CacheInitializationError: () => CacheInitializationError,
|
|
38
|
+
CacheOperationError: () => CacheOperationError,
|
|
39
|
+
FilesystemStorage: () => FilesystemStorage,
|
|
40
|
+
StorageNotInitializedError: () => StorageNotInitializedError,
|
|
41
|
+
createFilesystemStorage: () => createFilesystemStorage
|
|
42
|
+
});
|
|
43
|
+
import { mkdir, readFile, writeFile, readdir, unlink, rm } from "fs/promises";
|
|
44
|
+
import { join, dirname } from "path";
|
|
45
|
+
import { existsSync } from "fs";
|
|
46
|
+
import { createHash } from "crypto";
|
|
47
|
+
function createFilesystemStorage(options) {
|
|
48
|
+
return new FilesystemStorage(options);
|
|
49
|
+
}
|
|
50
|
+
var CacheInitializationError, CacheOperationError, StorageNotInitializedError, DEFAULT_FS_OPTIONS, FilesystemStorage;
|
|
51
|
+
var init_filesystem = __esm({
|
|
52
|
+
"libs/uipack/src/bundler/file-cache/storage/filesystem.ts"() {
|
|
53
|
+
"use strict";
|
|
54
|
+
init_interface();
|
|
55
|
+
CacheInitializationError = class extends Error {
|
|
56
|
+
cause;
|
|
57
|
+
constructor(message, cause) {
|
|
58
|
+
super(message);
|
|
59
|
+
this.name = "CacheInitializationError";
|
|
60
|
+
this.cause = cause;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
CacheOperationError = class extends Error {
|
|
64
|
+
cause;
|
|
65
|
+
constructor(message, cause) {
|
|
66
|
+
super(message);
|
|
67
|
+
this.name = "CacheOperationError";
|
|
68
|
+
this.cause = cause;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
StorageNotInitializedError = class extends Error {
|
|
72
|
+
constructor() {
|
|
73
|
+
super("Storage not initialized. Call initialize() first.");
|
|
74
|
+
this.name = "StorageNotInitializedError";
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
DEFAULT_FS_OPTIONS = {
|
|
78
|
+
...DEFAULT_STORAGE_OPTIONS,
|
|
79
|
+
cacheDir: ".frontmcp-cache/builds",
|
|
80
|
+
extension: ".json"
|
|
81
|
+
};
|
|
82
|
+
FilesystemStorage = class {
|
|
83
|
+
type = "filesystem";
|
|
84
|
+
options;
|
|
85
|
+
initialized = false;
|
|
86
|
+
stats = {
|
|
87
|
+
entries: 0,
|
|
88
|
+
totalSize: 0,
|
|
89
|
+
hits: 0,
|
|
90
|
+
misses: 0,
|
|
91
|
+
hitRate: 0
|
|
92
|
+
};
|
|
93
|
+
constructor(options = {}) {
|
|
94
|
+
this.options = {
|
|
95
|
+
...DEFAULT_FS_OPTIONS,
|
|
96
|
+
...options
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Initialize the storage directory.
|
|
101
|
+
*/
|
|
102
|
+
async initialize() {
|
|
103
|
+
if (this.initialized) return;
|
|
104
|
+
try {
|
|
105
|
+
await mkdir(this.options.cacheDir, { recursive: true });
|
|
106
|
+
await this.loadStats();
|
|
107
|
+
this.initialized = true;
|
|
108
|
+
} catch (error) {
|
|
109
|
+
throw new CacheInitializationError(`Failed to initialize cache directory: ${error}`, error);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get a cached manifest.
|
|
114
|
+
*/
|
|
115
|
+
async get(key) {
|
|
116
|
+
this.ensureInitialized();
|
|
117
|
+
const filePath = this.getFilePath(key);
|
|
118
|
+
try {
|
|
119
|
+
if (!existsSync(filePath)) {
|
|
120
|
+
this.stats.misses++;
|
|
121
|
+
this.updateHitRate();
|
|
122
|
+
return void 0;
|
|
123
|
+
}
|
|
124
|
+
const content = await readFile(filePath, "utf8");
|
|
125
|
+
const entry = JSON.parse(content);
|
|
126
|
+
if (Date.now() > entry.metadata.expiresAt) {
|
|
127
|
+
await this.delete(key);
|
|
128
|
+
this.stats.misses++;
|
|
129
|
+
this.updateHitRate();
|
|
130
|
+
return void 0;
|
|
131
|
+
}
|
|
132
|
+
entry.metadata.lastAccessedAt = Date.now();
|
|
133
|
+
entry.metadata.accessCount++;
|
|
134
|
+
this.writeEntry(filePath, entry).catch((err) => {
|
|
135
|
+
if (process.env["DEBUG"]) {
|
|
136
|
+
console.debug(`[FilesystemStorage] Failed to update cache metadata for ${key}: ${err}`);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
this.stats.hits++;
|
|
140
|
+
this.updateHitRate();
|
|
141
|
+
return entry.data;
|
|
142
|
+
} catch {
|
|
143
|
+
this.stats.misses++;
|
|
144
|
+
this.updateHitRate();
|
|
145
|
+
return void 0;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Store a manifest in cache.
|
|
150
|
+
*/
|
|
151
|
+
async set(key, manifest, ttl) {
|
|
152
|
+
this.ensureInitialized();
|
|
153
|
+
const filePath = this.getFilePath(key);
|
|
154
|
+
const size = calculateManifestSize(manifest);
|
|
155
|
+
const effectiveTtl = ttl ?? this.options.defaultTtl;
|
|
156
|
+
await this.ensureCapacity(size);
|
|
157
|
+
const entry = {
|
|
158
|
+
data: manifest,
|
|
159
|
+
metadata: {
|
|
160
|
+
key,
|
|
161
|
+
size,
|
|
162
|
+
createdAt: Date.now(),
|
|
163
|
+
expiresAt: Date.now() + effectiveTtl * 1e3,
|
|
164
|
+
lastAccessedAt: Date.now(),
|
|
165
|
+
accessCount: 0
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
await this.writeEntry(filePath, entry);
|
|
169
|
+
this.stats.entries++;
|
|
170
|
+
this.stats.totalSize += size;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Check if a key exists.
|
|
174
|
+
*/
|
|
175
|
+
async has(key) {
|
|
176
|
+
this.ensureInitialized();
|
|
177
|
+
const filePath = this.getFilePath(key);
|
|
178
|
+
try {
|
|
179
|
+
if (!existsSync(filePath)) return false;
|
|
180
|
+
const content = await readFile(filePath, "utf8");
|
|
181
|
+
const entry = JSON.parse(content);
|
|
182
|
+
if (Date.now() > entry.metadata.expiresAt) {
|
|
183
|
+
await this.delete(key);
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
return true;
|
|
187
|
+
} catch {
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Delete a cached entry.
|
|
193
|
+
*/
|
|
194
|
+
async delete(key) {
|
|
195
|
+
this.ensureInitialized();
|
|
196
|
+
const filePath = this.getFilePath(key);
|
|
197
|
+
try {
|
|
198
|
+
if (!existsSync(filePath)) return false;
|
|
199
|
+
const content = await readFile(filePath, "utf8");
|
|
200
|
+
const entry = JSON.parse(content);
|
|
201
|
+
await unlink(filePath);
|
|
202
|
+
this.stats.entries = Math.max(0, this.stats.entries - 1);
|
|
203
|
+
this.stats.totalSize = Math.max(0, this.stats.totalSize - entry.metadata.size);
|
|
204
|
+
return true;
|
|
205
|
+
} catch {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Clear all cached entries.
|
|
211
|
+
*/
|
|
212
|
+
async clear() {
|
|
213
|
+
this.ensureInitialized();
|
|
214
|
+
try {
|
|
215
|
+
await rm(this.options.cacheDir, { recursive: true, force: true });
|
|
216
|
+
await mkdir(this.options.cacheDir, { recursive: true });
|
|
217
|
+
this.stats = {
|
|
218
|
+
entries: 0,
|
|
219
|
+
totalSize: 0,
|
|
220
|
+
hits: 0,
|
|
221
|
+
misses: 0,
|
|
222
|
+
hitRate: 0
|
|
223
|
+
};
|
|
224
|
+
} catch (error) {
|
|
225
|
+
throw new CacheOperationError(`Failed to clear cache: ${error}`, error);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Get cache statistics.
|
|
230
|
+
*/
|
|
231
|
+
async getStats() {
|
|
232
|
+
return { ...this.stats };
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Clean up expired entries.
|
|
236
|
+
*/
|
|
237
|
+
async cleanup() {
|
|
238
|
+
this.ensureInitialized();
|
|
239
|
+
let removed = 0;
|
|
240
|
+
try {
|
|
241
|
+
const files = await readdir(this.options.cacheDir);
|
|
242
|
+
for (const file of files) {
|
|
243
|
+
if (!file.endsWith(this.options.extension)) continue;
|
|
244
|
+
const filePath = join(this.options.cacheDir, file);
|
|
245
|
+
try {
|
|
246
|
+
const content = await readFile(filePath, "utf8");
|
|
247
|
+
const entry = JSON.parse(content);
|
|
248
|
+
if (Date.now() > entry.metadata.expiresAt) {
|
|
249
|
+
await unlink(filePath);
|
|
250
|
+
this.stats.entries = Math.max(0, this.stats.entries - 1);
|
|
251
|
+
this.stats.totalSize = Math.max(0, this.stats.totalSize - entry.metadata.size);
|
|
252
|
+
removed++;
|
|
253
|
+
}
|
|
254
|
+
} catch {
|
|
255
|
+
await unlink(filePath).catch(() => {
|
|
256
|
+
});
|
|
257
|
+
removed++;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
} catch {
|
|
261
|
+
}
|
|
262
|
+
return removed;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Close the storage (no-op for filesystem).
|
|
266
|
+
*/
|
|
267
|
+
async close() {
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Get the file path for a cache key.
|
|
271
|
+
* Uses SHA-256 hash to avoid collisions from key sanitization.
|
|
272
|
+
*/
|
|
273
|
+
getFilePath(key) {
|
|
274
|
+
const hash = createHash("sha256").update(key).digest("hex").slice(0, 16);
|
|
275
|
+
return join(this.options.cacheDir, `${hash}${this.options.extension}`);
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Write a cache entry to disk.
|
|
279
|
+
*/
|
|
280
|
+
async writeEntry(filePath, entry) {
|
|
281
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
282
|
+
await writeFile(filePath, JSON.stringify(entry, null, 2), "utf8");
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Ensure the storage is initialized.
|
|
286
|
+
*/
|
|
287
|
+
ensureInitialized() {
|
|
288
|
+
if (!this.initialized) {
|
|
289
|
+
throw new StorageNotInitializedError();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Load stats from existing cache files.
|
|
294
|
+
* Reads entry metadata to get accurate manifest sizes.
|
|
295
|
+
*/
|
|
296
|
+
async loadStats() {
|
|
297
|
+
try {
|
|
298
|
+
const files = await readdir(this.options.cacheDir);
|
|
299
|
+
let entries = 0;
|
|
300
|
+
let totalSize = 0;
|
|
301
|
+
for (const file of files) {
|
|
302
|
+
if (!file.endsWith(this.options.extension)) continue;
|
|
303
|
+
const filePath = join(this.options.cacheDir, file);
|
|
304
|
+
try {
|
|
305
|
+
const content = await readFile(filePath, "utf8");
|
|
306
|
+
const entry = JSON.parse(content);
|
|
307
|
+
entries++;
|
|
308
|
+
totalSize += entry.metadata.size;
|
|
309
|
+
} catch {
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
this.stats.entries = entries;
|
|
313
|
+
this.stats.totalSize = totalSize;
|
|
314
|
+
} catch {
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Ensure there's capacity for a new entry.
|
|
319
|
+
*/
|
|
320
|
+
async ensureCapacity(newEntrySize) {
|
|
321
|
+
if (this.stats.entries >= this.options.maxEntries) {
|
|
322
|
+
await this.evictLRU();
|
|
323
|
+
}
|
|
324
|
+
while (this.stats.totalSize + newEntrySize > this.options.maxSize) {
|
|
325
|
+
const evicted = await this.evictLRU();
|
|
326
|
+
if (!evicted) break;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Evict the least recently used entry.
|
|
331
|
+
*/
|
|
332
|
+
async evictLRU() {
|
|
333
|
+
try {
|
|
334
|
+
const files = await readdir(this.options.cacheDir);
|
|
335
|
+
let oldestKey = null;
|
|
336
|
+
let oldestTime = Infinity;
|
|
337
|
+
let corruptedFile = null;
|
|
338
|
+
for (const file of files) {
|
|
339
|
+
if (!file.endsWith(this.options.extension)) continue;
|
|
340
|
+
const filePath = join(this.options.cacheDir, file);
|
|
341
|
+
try {
|
|
342
|
+
const content = await readFile(filePath, "utf8");
|
|
343
|
+
const entry = JSON.parse(content);
|
|
344
|
+
if (entry.metadata.lastAccessedAt < oldestTime) {
|
|
345
|
+
oldestTime = entry.metadata.lastAccessedAt;
|
|
346
|
+
oldestKey = entry.metadata.key;
|
|
347
|
+
}
|
|
348
|
+
} catch {
|
|
349
|
+
corruptedFile = filePath;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
if (corruptedFile) {
|
|
353
|
+
try {
|
|
354
|
+
await unlink(corruptedFile);
|
|
355
|
+
this.stats.entries = Math.max(0, this.stats.entries - 1);
|
|
356
|
+
return true;
|
|
357
|
+
} catch {
|
|
358
|
+
return false;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
if (oldestKey) {
|
|
362
|
+
return await this.delete(oldestKey);
|
|
363
|
+
}
|
|
364
|
+
return false;
|
|
365
|
+
} catch {
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Update hit rate statistic.
|
|
371
|
+
*/
|
|
372
|
+
updateHitRate() {
|
|
373
|
+
const total = this.stats.hits + this.stats.misses;
|
|
374
|
+
this.stats.hitRate = total > 0 ? this.stats.hits / total : 0;
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
// libs/uipack/src/bundler/file-cache/storage/redis.ts
|
|
381
|
+
var redis_exports = {};
|
|
382
|
+
__export(redis_exports, {
|
|
383
|
+
RedisStorage: () => RedisStorage,
|
|
384
|
+
createRedisStorage: () => createRedisStorage
|
|
385
|
+
});
|
|
386
|
+
function createRedisStorage(options) {
|
|
387
|
+
return new RedisStorage(options);
|
|
388
|
+
}
|
|
389
|
+
var STATS_KEY_SUFFIX, RedisStorage;
|
|
390
|
+
var init_redis = __esm({
|
|
391
|
+
"libs/uipack/src/bundler/file-cache/storage/redis.ts"() {
|
|
392
|
+
"use strict";
|
|
393
|
+
init_interface();
|
|
394
|
+
STATS_KEY_SUFFIX = ":__stats__";
|
|
395
|
+
RedisStorage = class {
|
|
396
|
+
type = "redis";
|
|
397
|
+
options;
|
|
398
|
+
initialized = false;
|
|
399
|
+
localStats = {
|
|
400
|
+
entries: 0,
|
|
401
|
+
totalSize: 0,
|
|
402
|
+
hits: 0,
|
|
403
|
+
misses: 0,
|
|
404
|
+
hitRate: 0
|
|
405
|
+
};
|
|
406
|
+
constructor(options) {
|
|
407
|
+
if (!options.client) {
|
|
408
|
+
throw new Error("Redis client is required");
|
|
409
|
+
}
|
|
410
|
+
this.options = {
|
|
411
|
+
...DEFAULT_STORAGE_OPTIONS,
|
|
412
|
+
keyPrefix: "frontmcp:ui:build:",
|
|
413
|
+
json: true,
|
|
414
|
+
...options
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Initialize the Redis connection.
|
|
419
|
+
*/
|
|
420
|
+
async initialize() {
|
|
421
|
+
if (this.initialized) return;
|
|
422
|
+
try {
|
|
423
|
+
await this.options.client.ping();
|
|
424
|
+
await this.loadStats();
|
|
425
|
+
this.initialized = true;
|
|
426
|
+
} catch (error) {
|
|
427
|
+
throw new Error(`Failed to connect to Redis: ${error}`);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Get a cached manifest.
|
|
432
|
+
*/
|
|
433
|
+
async get(key) {
|
|
434
|
+
this.ensureInitialized();
|
|
435
|
+
const redisKey = this.getRedisKey(key);
|
|
436
|
+
try {
|
|
437
|
+
const data = await this.options.client.get(redisKey);
|
|
438
|
+
if (!data) {
|
|
439
|
+
this.localStats.misses++;
|
|
440
|
+
this.updateHitRate();
|
|
441
|
+
await this.persistStats();
|
|
442
|
+
return void 0;
|
|
443
|
+
}
|
|
444
|
+
const entry = JSON.parse(data);
|
|
445
|
+
entry.metadata.lastAccessedAt = Date.now();
|
|
446
|
+
entry.metadata.accessCount++;
|
|
447
|
+
const ttl = await this.options.client.ttl(redisKey);
|
|
448
|
+
if (ttl > 0) {
|
|
449
|
+
const serialized = JSON.stringify(entry);
|
|
450
|
+
await this.options.client.setex(redisKey, ttl, serialized);
|
|
451
|
+
}
|
|
452
|
+
this.localStats.hits++;
|
|
453
|
+
this.updateHitRate();
|
|
454
|
+
await this.persistStats();
|
|
455
|
+
return entry.data;
|
|
456
|
+
} catch (error) {
|
|
457
|
+
console.warn?.(`Redis cache get failed for key "${key}": ${error}`);
|
|
458
|
+
this.localStats.misses++;
|
|
459
|
+
this.updateHitRate();
|
|
460
|
+
await this.persistStats().catch(() => {
|
|
461
|
+
});
|
|
462
|
+
return void 0;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Store a manifest in cache.
|
|
467
|
+
*/
|
|
468
|
+
async set(key, manifest, ttl) {
|
|
469
|
+
this.ensureInitialized();
|
|
470
|
+
const redisKey = this.getRedisKey(key);
|
|
471
|
+
const size = calculateManifestSize(manifest);
|
|
472
|
+
const effectiveTtl = ttl ?? this.options.defaultTtl;
|
|
473
|
+
const entry = {
|
|
474
|
+
data: manifest,
|
|
475
|
+
metadata: {
|
|
476
|
+
key,
|
|
477
|
+
size,
|
|
478
|
+
createdAt: Date.now(),
|
|
479
|
+
expiresAt: Date.now() + effectiveTtl * 1e3,
|
|
480
|
+
lastAccessedAt: Date.now(),
|
|
481
|
+
accessCount: 0
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
const serialized = JSON.stringify(entry);
|
|
485
|
+
await this.options.client.setex(redisKey, effectiveTtl, serialized);
|
|
486
|
+
this.localStats.entries++;
|
|
487
|
+
this.localStats.totalSize += size;
|
|
488
|
+
await this.persistStats();
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Check if a key exists.
|
|
492
|
+
*/
|
|
493
|
+
async has(key) {
|
|
494
|
+
this.ensureInitialized();
|
|
495
|
+
const redisKey = this.getRedisKey(key);
|
|
496
|
+
const exists = await this.options.client.exists(redisKey);
|
|
497
|
+
return exists > 0;
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Delete a cached entry.
|
|
501
|
+
*/
|
|
502
|
+
async delete(key) {
|
|
503
|
+
this.ensureInitialized();
|
|
504
|
+
const redisKey = this.getRedisKey(key);
|
|
505
|
+
try {
|
|
506
|
+
const data = await this.options.client.get(redisKey);
|
|
507
|
+
if (data) {
|
|
508
|
+
const entry = JSON.parse(data);
|
|
509
|
+
this.localStats.totalSize = Math.max(0, this.localStats.totalSize - entry.metadata.size);
|
|
510
|
+
}
|
|
511
|
+
} catch {
|
|
512
|
+
}
|
|
513
|
+
const deleted = await this.options.client.del(redisKey);
|
|
514
|
+
if (deleted > 0) {
|
|
515
|
+
this.localStats.entries = Math.max(0, this.localStats.entries - 1);
|
|
516
|
+
await this.persistStats();
|
|
517
|
+
return true;
|
|
518
|
+
}
|
|
519
|
+
return false;
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Clear all cached entries.
|
|
523
|
+
*/
|
|
524
|
+
async clear() {
|
|
525
|
+
this.ensureInitialized();
|
|
526
|
+
const pattern = `${this.options.keyPrefix}*`;
|
|
527
|
+
const keys = await this.options.client.keys(pattern);
|
|
528
|
+
if (keys.length > 0) {
|
|
529
|
+
await this.options.client.del(keys);
|
|
530
|
+
}
|
|
531
|
+
this.localStats = {
|
|
532
|
+
entries: 0,
|
|
533
|
+
totalSize: 0,
|
|
534
|
+
hits: 0,
|
|
535
|
+
misses: 0,
|
|
536
|
+
hitRate: 0
|
|
537
|
+
};
|
|
538
|
+
await this.persistStats();
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Get cache statistics.
|
|
542
|
+
*/
|
|
543
|
+
async getStats() {
|
|
544
|
+
await this.loadStats();
|
|
545
|
+
return { ...this.localStats };
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Clean up expired entries.
|
|
549
|
+
* Redis handles TTL expiration automatically, so this just refreshes stats.
|
|
550
|
+
*/
|
|
551
|
+
async cleanup() {
|
|
552
|
+
this.ensureInitialized();
|
|
553
|
+
const pattern = `${this.options.keyPrefix}*`;
|
|
554
|
+
const keys = await this.options.client.keys(pattern);
|
|
555
|
+
const dataKeys = keys.filter((k) => !k.endsWith(STATS_KEY_SUFFIX));
|
|
556
|
+
const previousCount = this.localStats.entries;
|
|
557
|
+
this.localStats.entries = dataKeys.length;
|
|
558
|
+
let totalSize = 0;
|
|
559
|
+
for (const key of dataKeys) {
|
|
560
|
+
try {
|
|
561
|
+
const data = await this.options.client.get(key);
|
|
562
|
+
if (data) {
|
|
563
|
+
const entry = JSON.parse(data);
|
|
564
|
+
totalSize += entry.metadata.size;
|
|
565
|
+
}
|
|
566
|
+
} catch {
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
this.localStats.totalSize = totalSize;
|
|
570
|
+
await this.persistStats();
|
|
571
|
+
return Math.max(0, previousCount - this.localStats.entries);
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Close the Redis connection.
|
|
575
|
+
*/
|
|
576
|
+
async close() {
|
|
577
|
+
await this.options.client.quit();
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Get the Redis key for a cache key.
|
|
581
|
+
*/
|
|
582
|
+
getRedisKey(key) {
|
|
583
|
+
return `${this.options.keyPrefix}${key}`;
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Get the Redis key for stats.
|
|
587
|
+
*/
|
|
588
|
+
getStatsKey() {
|
|
589
|
+
return `${this.options.keyPrefix}${STATS_KEY_SUFFIX}`;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Ensure the storage is initialized.
|
|
593
|
+
*/
|
|
594
|
+
ensureInitialized() {
|
|
595
|
+
if (!this.initialized) {
|
|
596
|
+
throw new Error("Storage not initialized. Call initialize() first.");
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Load stats from Redis.
|
|
601
|
+
*/
|
|
602
|
+
async loadStats() {
|
|
603
|
+
try {
|
|
604
|
+
const statsKey = this.getStatsKey();
|
|
605
|
+
const data = await this.options.client.get(statsKey);
|
|
606
|
+
if (data) {
|
|
607
|
+
const savedStats = JSON.parse(data);
|
|
608
|
+
this.localStats = {
|
|
609
|
+
...this.localStats,
|
|
610
|
+
...savedStats
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
} catch {
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Persist stats to Redis.
|
|
618
|
+
*/
|
|
619
|
+
async persistStats() {
|
|
620
|
+
try {
|
|
621
|
+
const statsKey = this.getStatsKey();
|
|
622
|
+
const serialized = JSON.stringify(this.localStats);
|
|
623
|
+
await this.options.client.set(statsKey, serialized);
|
|
624
|
+
} catch {
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Update hit rate statistic.
|
|
629
|
+
*/
|
|
630
|
+
updateHitRate() {
|
|
631
|
+
const total = this.localStats.hits + this.localStats.misses;
|
|
632
|
+
this.localStats.hitRate = total > 0 ? this.localStats.hits / total : 0;
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
// libs/uipack/src/bundler/types.ts
|
|
639
|
+
var DEFAULT_SECURITY_POLICY = {
|
|
640
|
+
allowedImports: [/^react$/, /^react-dom$/, /^react\/jsx-runtime$/, /^react\/jsx-dev-runtime$/, /^@frontmcp\/ui/],
|
|
641
|
+
blockedImports: [
|
|
642
|
+
/^fs$/,
|
|
643
|
+
/^fs\//,
|
|
644
|
+
/^net$/,
|
|
645
|
+
/^child_process$/,
|
|
646
|
+
/^os$/,
|
|
647
|
+
/^path$/,
|
|
648
|
+
/^crypto$/,
|
|
649
|
+
/^http$/,
|
|
650
|
+
/^https$/,
|
|
651
|
+
/^dgram$/,
|
|
652
|
+
/^dns$/,
|
|
653
|
+
/^cluster$/,
|
|
654
|
+
/^readline$/,
|
|
655
|
+
/^repl$/,
|
|
656
|
+
/^tls$/,
|
|
657
|
+
/^vm$/,
|
|
658
|
+
/^worker_threads$/
|
|
659
|
+
],
|
|
660
|
+
maxBundleSize: 512e3,
|
|
661
|
+
// 500KB
|
|
662
|
+
maxTransformTime: 5e3,
|
|
663
|
+
// 5s
|
|
664
|
+
noEval: true,
|
|
665
|
+
noDynamicImports: true,
|
|
666
|
+
noRequire: true,
|
|
667
|
+
allowedGlobals: [
|
|
668
|
+
"console",
|
|
669
|
+
"Math",
|
|
670
|
+
"JSON",
|
|
671
|
+
"Date",
|
|
672
|
+
"Array",
|
|
673
|
+
"Object",
|
|
674
|
+
"String",
|
|
675
|
+
"Number",
|
|
676
|
+
"Boolean",
|
|
677
|
+
"Promise",
|
|
678
|
+
"Map",
|
|
679
|
+
"Set",
|
|
680
|
+
"WeakMap",
|
|
681
|
+
"WeakSet",
|
|
682
|
+
"Symbol",
|
|
683
|
+
"Reflect",
|
|
684
|
+
"Proxy",
|
|
685
|
+
"Error",
|
|
686
|
+
"TypeError",
|
|
687
|
+
"RangeError",
|
|
688
|
+
"SyntaxError",
|
|
689
|
+
"ReferenceError",
|
|
690
|
+
"parseInt",
|
|
691
|
+
"parseFloat",
|
|
692
|
+
"isNaN",
|
|
693
|
+
"isFinite",
|
|
694
|
+
"encodeURI",
|
|
695
|
+
"encodeURIComponent",
|
|
696
|
+
"decodeURI",
|
|
697
|
+
"decodeURIComponent",
|
|
698
|
+
"setTimeout",
|
|
699
|
+
"clearTimeout",
|
|
700
|
+
"setInterval",
|
|
701
|
+
"clearInterval",
|
|
702
|
+
"atob",
|
|
703
|
+
"btoa",
|
|
704
|
+
"Intl",
|
|
705
|
+
"TextEncoder",
|
|
706
|
+
"TextDecoder",
|
|
707
|
+
"URL",
|
|
708
|
+
"URLSearchParams",
|
|
709
|
+
"Uint8Array",
|
|
710
|
+
"Int8Array",
|
|
711
|
+
"Uint16Array",
|
|
712
|
+
"Int16Array",
|
|
713
|
+
"Uint32Array",
|
|
714
|
+
"Int32Array",
|
|
715
|
+
"Float32Array",
|
|
716
|
+
"Float64Array",
|
|
717
|
+
"BigInt",
|
|
718
|
+
"BigInt64Array",
|
|
719
|
+
"BigUint64Array",
|
|
720
|
+
"ArrayBuffer",
|
|
721
|
+
"SharedArrayBuffer",
|
|
722
|
+
"DataView",
|
|
723
|
+
"queueMicrotask"
|
|
724
|
+
]
|
|
725
|
+
};
|
|
726
|
+
var DEFAULT_BUNDLE_OPTIONS = {
|
|
727
|
+
sourceType: "auto",
|
|
728
|
+
format: "iife",
|
|
729
|
+
minify: false,
|
|
730
|
+
sourceMaps: false,
|
|
731
|
+
externals: ["react", "react-dom"],
|
|
732
|
+
jsx: {
|
|
733
|
+
runtime: "automatic",
|
|
734
|
+
importSource: "react"
|
|
735
|
+
},
|
|
736
|
+
target: "es2020",
|
|
737
|
+
globalName: "Widget",
|
|
738
|
+
skipCache: false
|
|
739
|
+
};
|
|
740
|
+
var DEFAULT_BUNDLER_OPTIONS = {
|
|
741
|
+
defaultSecurity: DEFAULT_SECURITY_POLICY,
|
|
742
|
+
cache: {
|
|
743
|
+
maxSize: 100,
|
|
744
|
+
ttl: 3e5,
|
|
745
|
+
// 5 minutes
|
|
746
|
+
disabled: false
|
|
747
|
+
},
|
|
748
|
+
verbose: false,
|
|
749
|
+
esbuildOptions: {}
|
|
750
|
+
};
|
|
751
|
+
var STATIC_HTML_CDN = {
|
|
752
|
+
/**
|
|
753
|
+
* ES modules from esm.sh (React 19, modern platforms)
|
|
754
|
+
*/
|
|
755
|
+
esm: {
|
|
756
|
+
react: "https://esm.sh/react@19",
|
|
757
|
+
reactDom: "https://esm.sh/react-dom@19/client"
|
|
758
|
+
},
|
|
759
|
+
/**
|
|
760
|
+
* UMD builds from cdnjs (React 18.2, Claude only trusts cloudflare)
|
|
761
|
+
*/
|
|
762
|
+
umd: {
|
|
763
|
+
react: "https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js",
|
|
764
|
+
reactDom: "https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"
|
|
765
|
+
},
|
|
766
|
+
/**
|
|
767
|
+
* Tailwind CSS from cdnjs (cloudflare) - works on all platforms
|
|
768
|
+
* Using CSS file instead of JS browser version to avoid style normalization issues
|
|
769
|
+
*/
|
|
770
|
+
tailwind: "https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/3.4.1/tailwind.min.css",
|
|
771
|
+
/**
|
|
772
|
+
* Font CDN URLs
|
|
773
|
+
*/
|
|
774
|
+
fonts: {
|
|
775
|
+
preconnect: ["https://fonts.googleapis.com", "https://fonts.gstatic.com"],
|
|
776
|
+
inter: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
|
777
|
+
}
|
|
778
|
+
};
|
|
779
|
+
function getCdnTypeForPlatform(platform) {
|
|
780
|
+
if (platform === "claude") return "umd";
|
|
781
|
+
return "esm";
|
|
782
|
+
}
|
|
783
|
+
var DEFAULT_STATIC_HTML_OPTIONS = {
|
|
784
|
+
sourceType: "auto",
|
|
785
|
+
targetPlatform: "auto",
|
|
786
|
+
minify: true,
|
|
787
|
+
skipCache: false,
|
|
788
|
+
rootId: "frontmcp-widget-root",
|
|
789
|
+
widgetAccessible: false,
|
|
790
|
+
externals: {
|
|
791
|
+
react: "cdn",
|
|
792
|
+
reactDom: "cdn",
|
|
793
|
+
tailwind: "cdn",
|
|
794
|
+
frontmcpUi: "inline"
|
|
795
|
+
},
|
|
796
|
+
// Universal mode defaults
|
|
797
|
+
universal: false,
|
|
798
|
+
contentType: "auto",
|
|
799
|
+
includeMarkdown: false,
|
|
800
|
+
includeMdx: false
|
|
801
|
+
};
|
|
802
|
+
|
|
803
|
+
// libs/uipack/src/bundler/sandbox/policy.ts
|
|
804
|
+
var UNSAFE_PATTERNS = {
|
|
805
|
+
eval: /\beval\s*\(/g,
|
|
806
|
+
functionConstructor: /\bnew\s+Function\s*\(/g,
|
|
807
|
+
dynamicImport: /\bimport\s*\(/g,
|
|
808
|
+
require: /\brequire\s*\(/g,
|
|
809
|
+
processEnv: /\bprocess\.env\b/g,
|
|
810
|
+
globalThis: /\bglobalThis\b/g,
|
|
811
|
+
windowLocation: /\bwindow\.location\b/g,
|
|
812
|
+
documentCookie: /\bdocument\.cookie\b/g,
|
|
813
|
+
innerHTML: /\.innerHTML\s*=/g,
|
|
814
|
+
outerHTML: /\.outerHTML\s*=/g,
|
|
815
|
+
document_write: /\bdocument\.write\s*\(/g
|
|
816
|
+
};
|
|
817
|
+
function validateSource(source, policy = DEFAULT_SECURITY_POLICY) {
|
|
818
|
+
const violations = [];
|
|
819
|
+
if (policy.noEval !== false) {
|
|
820
|
+
const evalMatches = [...source.matchAll(UNSAFE_PATTERNS.eval)];
|
|
821
|
+
for (const match of evalMatches) {
|
|
822
|
+
violations.push({
|
|
823
|
+
type: "eval-usage",
|
|
824
|
+
message: "eval() is not allowed for security reasons",
|
|
825
|
+
location: getLocation(source, match.index ?? 0),
|
|
826
|
+
value: match[0]
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
const fnMatches = [...source.matchAll(UNSAFE_PATTERNS.functionConstructor)];
|
|
830
|
+
for (const match of fnMatches) {
|
|
831
|
+
violations.push({
|
|
832
|
+
type: "eval-usage",
|
|
833
|
+
message: "new Function() is not allowed for security reasons",
|
|
834
|
+
location: getLocation(source, match.index ?? 0),
|
|
835
|
+
value: match[0]
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
if (policy.noDynamicImports !== false) {
|
|
840
|
+
const matches = [...source.matchAll(UNSAFE_PATTERNS.dynamicImport)];
|
|
841
|
+
for (const match of matches) {
|
|
842
|
+
violations.push({
|
|
843
|
+
type: "dynamic-import",
|
|
844
|
+
message: "Dynamic imports are not allowed for security reasons",
|
|
845
|
+
location: getLocation(source, match.index ?? 0),
|
|
846
|
+
value: match[0]
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
if (policy.noRequire !== false) {
|
|
851
|
+
const matches = [...source.matchAll(UNSAFE_PATTERNS.require)];
|
|
852
|
+
for (const match of matches) {
|
|
853
|
+
violations.push({
|
|
854
|
+
type: "require-usage",
|
|
855
|
+
message: "require() is not allowed for security reasons",
|
|
856
|
+
location: getLocation(source, match.index ?? 0),
|
|
857
|
+
value: match[0]
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
const importViolations = validateImports(source, policy);
|
|
862
|
+
violations.push(...importViolations);
|
|
863
|
+
return violations;
|
|
864
|
+
}
|
|
865
|
+
function validateImports(source, policy = DEFAULT_SECURITY_POLICY) {
|
|
866
|
+
const violations = [];
|
|
867
|
+
const importPattern = /import\s+(?:(?:\{[^}]*\}|[\w*]+)\s+from\s+)?['"]([^'"]+)['"]/g;
|
|
868
|
+
const imports = [];
|
|
869
|
+
let match;
|
|
870
|
+
while ((match = importPattern.exec(source)) !== null) {
|
|
871
|
+
imports.push({ module: match[1], index: match.index });
|
|
872
|
+
}
|
|
873
|
+
const requirePattern = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
874
|
+
while ((match = requirePattern.exec(source)) !== null) {
|
|
875
|
+
imports.push({ module: match[1], index: match.index });
|
|
876
|
+
}
|
|
877
|
+
for (const imp of imports) {
|
|
878
|
+
if (policy.blockedImports) {
|
|
879
|
+
for (const blocked of policy.blockedImports) {
|
|
880
|
+
if (blocked.test(imp.module)) {
|
|
881
|
+
violations.push({
|
|
882
|
+
type: "blocked-import",
|
|
883
|
+
message: `Import '${imp.module}' is blocked by security policy`,
|
|
884
|
+
location: getLocation(source, imp.index),
|
|
885
|
+
value: imp.module
|
|
886
|
+
});
|
|
887
|
+
break;
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
if (policy.allowedImports && policy.allowedImports.length > 0) {
|
|
892
|
+
const isAllowed = policy.allowedImports.some((pattern) => pattern.test(imp.module));
|
|
893
|
+
if (!isAllowed) {
|
|
894
|
+
const alreadyBlocked = violations.some((v) => v.type === "blocked-import" && v.value === imp.module);
|
|
895
|
+
if (!alreadyBlocked) {
|
|
896
|
+
violations.push({
|
|
897
|
+
type: "disallowed-import",
|
|
898
|
+
message: `Import '${imp.module}' is not in the allowed imports list`,
|
|
899
|
+
location: getLocation(source, imp.index),
|
|
900
|
+
value: imp.module
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
return violations;
|
|
907
|
+
}
|
|
908
|
+
function validateSize(size, policy = DEFAULT_SECURITY_POLICY) {
|
|
909
|
+
const maxSize = policy.maxBundleSize ?? DEFAULT_SECURITY_POLICY.maxBundleSize ?? 512e3;
|
|
910
|
+
if (size > maxSize) {
|
|
911
|
+
return {
|
|
912
|
+
type: "size-exceeded",
|
|
913
|
+
message: `Bundle size (${formatBytes(size)}) exceeds maximum allowed (${formatBytes(maxSize)})`,
|
|
914
|
+
value: String(size)
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
return void 0;
|
|
918
|
+
}
|
|
919
|
+
function mergePolicy(userPolicy) {
|
|
920
|
+
if (!userPolicy) {
|
|
921
|
+
return { ...DEFAULT_SECURITY_POLICY };
|
|
922
|
+
}
|
|
923
|
+
return {
|
|
924
|
+
allowedImports: userPolicy.allowedImports ?? DEFAULT_SECURITY_POLICY.allowedImports,
|
|
925
|
+
blockedImports: userPolicy.blockedImports ?? DEFAULT_SECURITY_POLICY.blockedImports,
|
|
926
|
+
maxBundleSize: userPolicy.maxBundleSize ?? DEFAULT_SECURITY_POLICY.maxBundleSize,
|
|
927
|
+
maxTransformTime: userPolicy.maxTransformTime ?? DEFAULT_SECURITY_POLICY.maxTransformTime,
|
|
928
|
+
noEval: userPolicy.noEval ?? DEFAULT_SECURITY_POLICY.noEval,
|
|
929
|
+
noDynamicImports: userPolicy.noDynamicImports ?? DEFAULT_SECURITY_POLICY.noDynamicImports,
|
|
930
|
+
noRequire: userPolicy.noRequire ?? DEFAULT_SECURITY_POLICY.noRequire,
|
|
931
|
+
allowedGlobals: userPolicy.allowedGlobals ?? DEFAULT_SECURITY_POLICY.allowedGlobals
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
function getLocation(source, index) {
|
|
935
|
+
const lines = source.slice(0, index).split("\n");
|
|
936
|
+
return {
|
|
937
|
+
line: lines.length,
|
|
938
|
+
column: lines[lines.length - 1].length + 1
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
function formatBytes(bytes) {
|
|
942
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
943
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
944
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
945
|
+
}
|
|
946
|
+
var SecurityError = class extends Error {
|
|
947
|
+
violations;
|
|
948
|
+
constructor(message, violations) {
|
|
949
|
+
super(message);
|
|
950
|
+
this.name = "SecurityError";
|
|
951
|
+
this.violations = violations;
|
|
952
|
+
}
|
|
953
|
+
};
|
|
954
|
+
function throwOnViolations(violations) {
|
|
955
|
+
if (violations.length > 0) {
|
|
956
|
+
const message = violations.map((v) => v.message).join("; ");
|
|
957
|
+
throw new SecurityError(`Security policy violation: ${message}`, violations);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
// libs/uipack/src/bundler/sandbox/enclave-adapter.ts
|
|
962
|
+
import { Enclave } from "enclave-vm";
|
|
963
|
+
var DEFAULT_ENCLAVE_OPTIONS = {
|
|
964
|
+
securityLevel: "SECURE",
|
|
965
|
+
timeout: 5e3,
|
|
966
|
+
maxIterations: 1e4,
|
|
967
|
+
validate: true,
|
|
968
|
+
transform: true
|
|
969
|
+
};
|
|
970
|
+
var STRICT_SECURITY_BLOCKED_IMPORTS_THRESHOLD = 10;
|
|
971
|
+
function mapSecurityLevel(policy) {
|
|
972
|
+
if (policy?.blockedImports && policy.blockedImports.length > STRICT_SECURITY_BLOCKED_IMPORTS_THRESHOLD) {
|
|
973
|
+
return "STRICT";
|
|
974
|
+
}
|
|
975
|
+
return "SECURE";
|
|
976
|
+
}
|
|
977
|
+
function createJSXRuntime(React) {
|
|
978
|
+
const R = React;
|
|
979
|
+
return {
|
|
980
|
+
jsx: (type, props, key) => {
|
|
981
|
+
const { children, ...rest } = props;
|
|
982
|
+
return R.createElement(type, key ? { ...rest, key } : rest, children);
|
|
983
|
+
},
|
|
984
|
+
jsxs: (type, props, key) => {
|
|
985
|
+
const { children, ...rest } = props;
|
|
986
|
+
return R.createElement(type, key ? { ...rest, key } : rest, children);
|
|
987
|
+
},
|
|
988
|
+
jsxDEV: (type, props, key, _isStaticChildren, _source, _self) => {
|
|
989
|
+
const { children, ...rest } = props;
|
|
990
|
+
return R.createElement(type, key ? { ...rest, key } : rest, children);
|
|
991
|
+
},
|
|
992
|
+
Fragment: R.Fragment
|
|
993
|
+
};
|
|
994
|
+
}
|
|
995
|
+
var DANGEROUS_GLOBAL_KEYS = /* @__PURE__ */ new Set([
|
|
996
|
+
"process",
|
|
997
|
+
"require",
|
|
998
|
+
"__dirname",
|
|
999
|
+
"__filename",
|
|
1000
|
+
"Buffer",
|
|
1001
|
+
"eval",
|
|
1002
|
+
"Function",
|
|
1003
|
+
"constructor",
|
|
1004
|
+
"global",
|
|
1005
|
+
"globalThis",
|
|
1006
|
+
"module",
|
|
1007
|
+
"exports",
|
|
1008
|
+
"__proto__"
|
|
1009
|
+
]);
|
|
1010
|
+
function sanitizeGlobalKey(key) {
|
|
1011
|
+
return key.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
1012
|
+
}
|
|
1013
|
+
function buildGlobals(context) {
|
|
1014
|
+
const globals = {};
|
|
1015
|
+
if (context.React) {
|
|
1016
|
+
globals["React"] = context.React;
|
|
1017
|
+
}
|
|
1018
|
+
if (context.ReactDOM) {
|
|
1019
|
+
globals["ReactDOM"] = context.ReactDOM;
|
|
1020
|
+
}
|
|
1021
|
+
if (context.React) {
|
|
1022
|
+
const jsxRuntime = createJSXRuntime(context.React);
|
|
1023
|
+
globals["__jsx"] = jsxRuntime["jsx"];
|
|
1024
|
+
globals["__jsxs"] = jsxRuntime["jsxs"];
|
|
1025
|
+
globals["__jsxDEV"] = jsxRuntime["jsxDEV"];
|
|
1026
|
+
globals["Fragment"] = jsxRuntime["Fragment"];
|
|
1027
|
+
}
|
|
1028
|
+
if (context.modules) {
|
|
1029
|
+
for (const [key, value] of Object.entries(context.modules)) {
|
|
1030
|
+
const sanitizedKey = sanitizeGlobalKey(key);
|
|
1031
|
+
if (DANGEROUS_GLOBAL_KEYS.has(sanitizedKey)) {
|
|
1032
|
+
throw new ExecutionError(
|
|
1033
|
+
`Dangerous module key '${key}' (sanitized: '${sanitizedKey}') is not allowed in execution context`,
|
|
1034
|
+
{ code: "SECURITY_VIOLATION" }
|
|
1035
|
+
);
|
|
1036
|
+
}
|
|
1037
|
+
globals[sanitizedKey] = value;
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
if (context.globals) {
|
|
1041
|
+
for (const [key, value] of Object.entries(context.globals)) {
|
|
1042
|
+
if (DANGEROUS_GLOBAL_KEYS.has(key)) {
|
|
1043
|
+
throw new ExecutionError(`Dangerous global key '${key}' is not allowed in execution context`, {
|
|
1044
|
+
code: "SECURITY_VIOLATION"
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
const sanitizedKey = sanitizeGlobalKey(key);
|
|
1048
|
+
if (DANGEROUS_GLOBAL_KEYS.has(sanitizedKey)) {
|
|
1049
|
+
throw new ExecutionError(
|
|
1050
|
+
`Dangerous global key '${key}' (sanitized: '${sanitizedKey}') is not allowed in execution context`,
|
|
1051
|
+
{ code: "SECURITY_VIOLATION" }
|
|
1052
|
+
);
|
|
1053
|
+
}
|
|
1054
|
+
globals[sanitizedKey] = value;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
return globals;
|
|
1058
|
+
}
|
|
1059
|
+
function buildRequireFunction(context) {
|
|
1060
|
+
const normalizedContextModules = {};
|
|
1061
|
+
if (context.modules) {
|
|
1062
|
+
for (const [key, value] of Object.entries(context.modules)) {
|
|
1063
|
+
normalizedContextModules[key.toLowerCase()] = value;
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
const modules = {
|
|
1067
|
+
react: context.React,
|
|
1068
|
+
"react-dom": context.ReactDOM,
|
|
1069
|
+
"react/jsx-runtime": context.React ? createJSXRuntime(context.React) : void 0,
|
|
1070
|
+
"react/jsx-dev-runtime": context.React ? createJSXRuntime(context.React) : void 0,
|
|
1071
|
+
...normalizedContextModules
|
|
1072
|
+
};
|
|
1073
|
+
return (id) => {
|
|
1074
|
+
const normalizedId = id.toLowerCase();
|
|
1075
|
+
if (normalizedId in modules) {
|
|
1076
|
+
const mod = modules[normalizedId];
|
|
1077
|
+
if (mod === void 0) {
|
|
1078
|
+
throw new Error(`Module '${id}' is not available. Did you forget to provide it in the context?`);
|
|
1079
|
+
}
|
|
1080
|
+
return mod;
|
|
1081
|
+
}
|
|
1082
|
+
throw new Error(`Module '${id}' is not available in the sandbox environment`);
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
async function executeCode(code, context = {}) {
|
|
1086
|
+
const consoleOutput = [];
|
|
1087
|
+
const globals = buildGlobals(context);
|
|
1088
|
+
globals["console"] = {
|
|
1089
|
+
log: (...args) => {
|
|
1090
|
+
consoleOutput.push(args.map(String).join(" "));
|
|
1091
|
+
},
|
|
1092
|
+
info: (...args) => {
|
|
1093
|
+
consoleOutput.push(`[INFO] ${args.map(String).join(" ")}`);
|
|
1094
|
+
},
|
|
1095
|
+
warn: (...args) => {
|
|
1096
|
+
consoleOutput.push(`[WARN] ${args.map(String).join(" ")}`);
|
|
1097
|
+
},
|
|
1098
|
+
error: (...args) => {
|
|
1099
|
+
consoleOutput.push(`[ERROR] ${args.map(String).join(" ")}`);
|
|
1100
|
+
},
|
|
1101
|
+
debug: (...args) => {
|
|
1102
|
+
consoleOutput.push(`[DEBUG] ${args.map(String).join(" ")}`);
|
|
1103
|
+
},
|
|
1104
|
+
trace: () => {
|
|
1105
|
+
},
|
|
1106
|
+
dir: () => {
|
|
1107
|
+
},
|
|
1108
|
+
table: () => {
|
|
1109
|
+
},
|
|
1110
|
+
group: () => {
|
|
1111
|
+
},
|
|
1112
|
+
groupEnd: () => {
|
|
1113
|
+
},
|
|
1114
|
+
time: () => {
|
|
1115
|
+
},
|
|
1116
|
+
timeEnd: () => {
|
|
1117
|
+
},
|
|
1118
|
+
assert: () => {
|
|
1119
|
+
},
|
|
1120
|
+
clear: () => {
|
|
1121
|
+
},
|
|
1122
|
+
count: () => {
|
|
1123
|
+
},
|
|
1124
|
+
countReset: () => {
|
|
1125
|
+
}
|
|
1126
|
+
};
|
|
1127
|
+
globals["require"] = buildRequireFunction(context);
|
|
1128
|
+
const enclave = new Enclave({
|
|
1129
|
+
...DEFAULT_ENCLAVE_OPTIONS,
|
|
1130
|
+
timeout: context.timeout ?? DEFAULT_ENCLAVE_OPTIONS.timeout,
|
|
1131
|
+
maxIterations: context.maxIterations ?? DEFAULT_ENCLAVE_OPTIONS.maxIterations,
|
|
1132
|
+
securityLevel: mapSecurityLevel(context.security),
|
|
1133
|
+
globals,
|
|
1134
|
+
allowFunctionsInGlobals: true
|
|
1135
|
+
// Required for React components
|
|
1136
|
+
});
|
|
1137
|
+
try {
|
|
1138
|
+
const wrappedCode = `
|
|
1139
|
+
const module = { exports: {} };
|
|
1140
|
+
const exports = module.exports;
|
|
1141
|
+
const __filename = 'widget.js';
|
|
1142
|
+
const __dirname = '/';
|
|
1143
|
+
${code}
|
|
1144
|
+
return module.exports;
|
|
1145
|
+
`;
|
|
1146
|
+
const result = await enclave.run(wrappedCode);
|
|
1147
|
+
if (!result.success) {
|
|
1148
|
+
const errorMessage = result.error?.message ?? "Execution failed";
|
|
1149
|
+
const errorCode = result.error?.code;
|
|
1150
|
+
if (errorCode === "TIMEOUT") {
|
|
1151
|
+
throw new ExecutionError(`Execution timed out after ${context.timeout ?? DEFAULT_ENCLAVE_OPTIONS.timeout}ms`, {
|
|
1152
|
+
code: "TIMEOUT"
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
1155
|
+
if (errorCode === "MAX_ITERATIONS") {
|
|
1156
|
+
throw new ExecutionError(
|
|
1157
|
+
`Maximum iterations exceeded (${context.maxIterations ?? DEFAULT_ENCLAVE_OPTIONS.maxIterations})`,
|
|
1158
|
+
{
|
|
1159
|
+
code: "MAX_ITERATIONS"
|
|
1160
|
+
}
|
|
1161
|
+
);
|
|
1162
|
+
}
|
|
1163
|
+
if (errorCode === "VALIDATION_ERROR") {
|
|
1164
|
+
throw new ExecutionError(`Security validation failed: ${errorMessage}`, { code: "SECURITY_VIOLATION" });
|
|
1165
|
+
}
|
|
1166
|
+
throw new ExecutionError(errorMessage, result.error);
|
|
1167
|
+
}
|
|
1168
|
+
return {
|
|
1169
|
+
exports: result.value,
|
|
1170
|
+
executionTime: result.stats.duration,
|
|
1171
|
+
consoleOutput: consoleOutput.length > 0 ? consoleOutput : void 0
|
|
1172
|
+
};
|
|
1173
|
+
} finally {
|
|
1174
|
+
enclave.dispose();
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
async function executeDefault(code, context = {}) {
|
|
1178
|
+
const result = await executeCode(code, context);
|
|
1179
|
+
if ("default" in result.exports) {
|
|
1180
|
+
return result.exports.default;
|
|
1181
|
+
}
|
|
1182
|
+
const exportKeys = Object.keys(result.exports);
|
|
1183
|
+
if (exportKeys.length === 0) {
|
|
1184
|
+
throw new ExecutionError("Code did not export any values");
|
|
1185
|
+
}
|
|
1186
|
+
if (exportKeys.length === 1) {
|
|
1187
|
+
return result.exports[exportKeys[0]];
|
|
1188
|
+
}
|
|
1189
|
+
return result.exports;
|
|
1190
|
+
}
|
|
1191
|
+
var ExecutionError = class extends Error {
|
|
1192
|
+
/** Error code for categorization */
|
|
1193
|
+
code;
|
|
1194
|
+
constructor(message, cause) {
|
|
1195
|
+
super(message, { cause });
|
|
1196
|
+
this.name = "ExecutionError";
|
|
1197
|
+
if (cause && typeof cause === "object" && "code" in cause) {
|
|
1198
|
+
this.code = cause.code;
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
};
|
|
1202
|
+
function isExecutionError(error) {
|
|
1203
|
+
return error instanceof ExecutionError;
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
// libs/uipack/src/bundler/cache.ts
|
|
1207
|
+
var BundlerCache = class {
|
|
1208
|
+
cache = /* @__PURE__ */ new Map();
|
|
1209
|
+
options;
|
|
1210
|
+
stats = {
|
|
1211
|
+
hits: 0,
|
|
1212
|
+
misses: 0,
|
|
1213
|
+
evictions: 0
|
|
1214
|
+
};
|
|
1215
|
+
constructor(options = {}) {
|
|
1216
|
+
this.options = {
|
|
1217
|
+
maxSize: options.maxSize ?? 100,
|
|
1218
|
+
ttl: options.ttl ?? 3e5
|
|
1219
|
+
};
|
|
1220
|
+
}
|
|
1221
|
+
/**
|
|
1222
|
+
* Get a cached bundle result.
|
|
1223
|
+
*
|
|
1224
|
+
* @param key - Cache key (typically content hash)
|
|
1225
|
+
* @returns Cached result or undefined if not found/expired
|
|
1226
|
+
*/
|
|
1227
|
+
get(key) {
|
|
1228
|
+
const entry = this.cache.get(key);
|
|
1229
|
+
if (!entry) {
|
|
1230
|
+
this.stats.misses++;
|
|
1231
|
+
return void 0;
|
|
1232
|
+
}
|
|
1233
|
+
if (this.isExpired(entry)) {
|
|
1234
|
+
this.cache.delete(key);
|
|
1235
|
+
this.stats.misses++;
|
|
1236
|
+
this.stats.evictions++;
|
|
1237
|
+
return void 0;
|
|
1238
|
+
}
|
|
1239
|
+
entry.lastAccessedAt = Date.now();
|
|
1240
|
+
entry.accessCount++;
|
|
1241
|
+
this.stats.hits++;
|
|
1242
|
+
this.cache.delete(key);
|
|
1243
|
+
this.cache.set(key, entry);
|
|
1244
|
+
return entry.result;
|
|
1245
|
+
}
|
|
1246
|
+
/**
|
|
1247
|
+
* Store a bundle result in the cache.
|
|
1248
|
+
*
|
|
1249
|
+
* @param key - Cache key (typically content hash)
|
|
1250
|
+
* @param result - Bundle result to cache
|
|
1251
|
+
*/
|
|
1252
|
+
set(key, result) {
|
|
1253
|
+
while (this.cache.size >= this.options.maxSize) {
|
|
1254
|
+
this.evictOldest();
|
|
1255
|
+
}
|
|
1256
|
+
const now = Date.now();
|
|
1257
|
+
const entry = {
|
|
1258
|
+
result,
|
|
1259
|
+
createdAt: now,
|
|
1260
|
+
lastAccessedAt: now,
|
|
1261
|
+
accessCount: 1
|
|
1262
|
+
};
|
|
1263
|
+
this.cache.set(key, entry);
|
|
1264
|
+
}
|
|
1265
|
+
/**
|
|
1266
|
+
* Check if a key exists in the cache (and is not expired).
|
|
1267
|
+
*
|
|
1268
|
+
* @param key - Cache key to check
|
|
1269
|
+
* @returns true if key exists and is not expired
|
|
1270
|
+
*/
|
|
1271
|
+
has(key) {
|
|
1272
|
+
const entry = this.cache.get(key);
|
|
1273
|
+
if (!entry) return false;
|
|
1274
|
+
if (this.isExpired(entry)) {
|
|
1275
|
+
this.cache.delete(key);
|
|
1276
|
+
this.stats.evictions++;
|
|
1277
|
+
return false;
|
|
1278
|
+
}
|
|
1279
|
+
return true;
|
|
1280
|
+
}
|
|
1281
|
+
/**
|
|
1282
|
+
* Delete a specific entry from the cache.
|
|
1283
|
+
*
|
|
1284
|
+
* @param key - Cache key to delete
|
|
1285
|
+
* @returns true if the key was found and deleted
|
|
1286
|
+
*/
|
|
1287
|
+
delete(key) {
|
|
1288
|
+
return this.cache.delete(key);
|
|
1289
|
+
}
|
|
1290
|
+
/**
|
|
1291
|
+
* Clear all entries from the cache.
|
|
1292
|
+
*/
|
|
1293
|
+
clear() {
|
|
1294
|
+
this.cache.clear();
|
|
1295
|
+
this.stats = {
|
|
1296
|
+
hits: 0,
|
|
1297
|
+
misses: 0,
|
|
1298
|
+
evictions: 0
|
|
1299
|
+
};
|
|
1300
|
+
}
|
|
1301
|
+
/**
|
|
1302
|
+
* Get cache statistics.
|
|
1303
|
+
*
|
|
1304
|
+
* @returns Current cache statistics
|
|
1305
|
+
*/
|
|
1306
|
+
getStats() {
|
|
1307
|
+
const total = this.stats.hits + this.stats.misses;
|
|
1308
|
+
const hitRate = total > 0 ? this.stats.hits / total : 0;
|
|
1309
|
+
let memoryUsage = 0;
|
|
1310
|
+
for (const entry of this.cache.values()) {
|
|
1311
|
+
memoryUsage += entry.result.size;
|
|
1312
|
+
if (entry.result.map) {
|
|
1313
|
+
memoryUsage += entry.result.map.length;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
return {
|
|
1317
|
+
size: this.cache.size,
|
|
1318
|
+
hits: this.stats.hits,
|
|
1319
|
+
misses: this.stats.misses,
|
|
1320
|
+
hitRate,
|
|
1321
|
+
evictions: this.stats.evictions,
|
|
1322
|
+
memoryUsage
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
/**
|
|
1326
|
+
* Remove expired entries from the cache.
|
|
1327
|
+
*
|
|
1328
|
+
* @returns Number of entries removed
|
|
1329
|
+
*/
|
|
1330
|
+
cleanup() {
|
|
1331
|
+
let removed = 0;
|
|
1332
|
+
for (const [key, entry] of this.cache.entries()) {
|
|
1333
|
+
if (this.isExpired(entry)) {
|
|
1334
|
+
this.cache.delete(key);
|
|
1335
|
+
removed++;
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
this.stats.evictions += removed;
|
|
1339
|
+
return removed;
|
|
1340
|
+
}
|
|
1341
|
+
/**
|
|
1342
|
+
* Get all cache keys.
|
|
1343
|
+
*
|
|
1344
|
+
* @returns Array of cache keys
|
|
1345
|
+
*/
|
|
1346
|
+
keys() {
|
|
1347
|
+
return Array.from(this.cache.keys());
|
|
1348
|
+
}
|
|
1349
|
+
/**
|
|
1350
|
+
* Get the number of entries in the cache.
|
|
1351
|
+
*/
|
|
1352
|
+
get size() {
|
|
1353
|
+
return this.cache.size;
|
|
1354
|
+
}
|
|
1355
|
+
/**
|
|
1356
|
+
* Check if an entry is expired.
|
|
1357
|
+
*/
|
|
1358
|
+
isExpired(entry) {
|
|
1359
|
+
return Date.now() - entry.createdAt > this.options.ttl;
|
|
1360
|
+
}
|
|
1361
|
+
/**
|
|
1362
|
+
* Evict the oldest (least recently used) entry.
|
|
1363
|
+
*/
|
|
1364
|
+
evictOldest() {
|
|
1365
|
+
const oldestKey = this.cache.keys().next().value;
|
|
1366
|
+
if (oldestKey !== void 0) {
|
|
1367
|
+
this.cache.delete(oldestKey);
|
|
1368
|
+
this.stats.evictions++;
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
};
|
|
1372
|
+
function hashContent(content) {
|
|
1373
|
+
let hash = 2166136261;
|
|
1374
|
+
for (let i = 0; i < content.length; i++) {
|
|
1375
|
+
hash ^= content.charCodeAt(i);
|
|
1376
|
+
hash = Math.imul(hash, 16777619);
|
|
1377
|
+
}
|
|
1378
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
1379
|
+
}
|
|
1380
|
+
function createCacheKey(source, options) {
|
|
1381
|
+
const sourceHash = hashContent(source);
|
|
1382
|
+
const optionsHash = hashContent(
|
|
1383
|
+
JSON.stringify({
|
|
1384
|
+
sourceType: options.sourceType,
|
|
1385
|
+
format: options.format,
|
|
1386
|
+
minify: options.minify,
|
|
1387
|
+
externals: options.externals?.slice().sort(),
|
|
1388
|
+
target: options.target
|
|
1389
|
+
})
|
|
1390
|
+
);
|
|
1391
|
+
return `${sourceHash}-${optionsHash}`;
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
// libs/uipack/src/bundler/file-cache/storage/index.ts
|
|
1395
|
+
init_interface();
|
|
1396
|
+
init_filesystem();
|
|
1397
|
+
init_redis();
|
|
1398
|
+
|
|
1399
|
+
// libs/uipack/src/bundler/file-cache/hash-calculator.ts
|
|
1400
|
+
import { createHash as createHash2 } from "crypto";
|
|
1401
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
1402
|
+
import { existsSync as existsSync2 } from "fs";
|
|
1403
|
+
import { join as join2, dirname as dirname2, resolve } from "path";
|
|
1404
|
+
function sha256(content) {
|
|
1405
|
+
return createHash2("sha256").update(content, "utf8").digest("hex");
|
|
1406
|
+
}
|
|
1407
|
+
function sha256Buffer(buffer) {
|
|
1408
|
+
return createHash2("sha256").update(buffer).digest("hex");
|
|
1409
|
+
}
|
|
1410
|
+
async function hashFile(filePath) {
|
|
1411
|
+
try {
|
|
1412
|
+
const content = await readFile2(filePath);
|
|
1413
|
+
return sha256Buffer(content);
|
|
1414
|
+
} catch {
|
|
1415
|
+
return void 0;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
async function hashFiles(filePaths) {
|
|
1419
|
+
const hashes = [];
|
|
1420
|
+
for (const filePath of filePaths.sort()) {
|
|
1421
|
+
const hash = await hashFile(filePath);
|
|
1422
|
+
if (hash) {
|
|
1423
|
+
hashes.push(`${filePath}:${hash}`);
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
return sha256(hashes.join("\n"));
|
|
1427
|
+
}
|
|
1428
|
+
async function calculateComponentHash(options) {
|
|
1429
|
+
const {
|
|
1430
|
+
entryPath,
|
|
1431
|
+
baseDir = dirname2(entryPath),
|
|
1432
|
+
externals = [],
|
|
1433
|
+
dependencies = {},
|
|
1434
|
+
bundleOptions = {},
|
|
1435
|
+
maxDepth = 10
|
|
1436
|
+
} = options;
|
|
1437
|
+
const absoluteEntryPath = resolve(entryPath);
|
|
1438
|
+
const files = /* @__PURE__ */ new Set();
|
|
1439
|
+
const fileHashes = {};
|
|
1440
|
+
await collectLocalDependencies(absoluteEntryPath, baseDir, files, maxDepth, 0);
|
|
1441
|
+
for (const file of files) {
|
|
1442
|
+
const hash = await hashFile(file);
|
|
1443
|
+
if (hash) {
|
|
1444
|
+
fileHashes[file] = hash;
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
const sortedFiles = Array.from(files).sort();
|
|
1448
|
+
const fileHashContent = sortedFiles.map((f) => `${f}:${fileHashes[f] || "missing"}`).join("\n");
|
|
1449
|
+
const filesHash = sha256(fileHashContent);
|
|
1450
|
+
const optionsHash = sha256(JSON.stringify(sortedObject(bundleOptions)));
|
|
1451
|
+
const dependenciesHash = sha256(JSON.stringify(sortedObject(dependencies)));
|
|
1452
|
+
const combinedHash = sha256([filesHash, optionsHash, dependenciesHash].join(":"));
|
|
1453
|
+
return {
|
|
1454
|
+
hash: combinedHash,
|
|
1455
|
+
entryHash: fileHashes[absoluteEntryPath] || "",
|
|
1456
|
+
files: sortedFiles,
|
|
1457
|
+
fileHashes,
|
|
1458
|
+
optionsHash,
|
|
1459
|
+
dependenciesHash
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1462
|
+
async function calculateQuickHash(entryPath, bundleOptions) {
|
|
1463
|
+
const entryHash = await hashFile(entryPath);
|
|
1464
|
+
const optionsHash = bundleOptions ? sha256(JSON.stringify(sortedObject(bundleOptions))) : "";
|
|
1465
|
+
return sha256(`${entryHash || "missing"}:${optionsHash}`);
|
|
1466
|
+
}
|
|
1467
|
+
async function collectLocalDependencies(filePath, baseDir, collected, maxDepth, currentDepth) {
|
|
1468
|
+
if (currentDepth >= maxDepth) return;
|
|
1469
|
+
if (collected.has(filePath)) return;
|
|
1470
|
+
if (!existsSync2(filePath)) return;
|
|
1471
|
+
collected.add(filePath);
|
|
1472
|
+
try {
|
|
1473
|
+
const content = await readFile2(filePath, "utf8");
|
|
1474
|
+
const imports = extractImportPaths(content);
|
|
1475
|
+
for (const importPath of imports) {
|
|
1476
|
+
if (!importPath.startsWith(".") && !importPath.startsWith("/")) {
|
|
1477
|
+
continue;
|
|
1478
|
+
}
|
|
1479
|
+
const resolvedPath = resolveImportPath(importPath, dirname2(filePath));
|
|
1480
|
+
if (resolvedPath && existsSync2(resolvedPath)) {
|
|
1481
|
+
await collectLocalDependencies(resolvedPath, baseDir, collected, maxDepth, currentDepth + 1);
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
} catch {
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
function extractImportPaths(source) {
|
|
1488
|
+
const paths = [];
|
|
1489
|
+
const importRegex = /import\s+(?:[^'"]+\s+from\s+)?['"]([^'"]+)['"]/g;
|
|
1490
|
+
let match;
|
|
1491
|
+
while ((match = importRegex.exec(source)) !== null) {
|
|
1492
|
+
paths.push(match[1]);
|
|
1493
|
+
}
|
|
1494
|
+
const exportRegex = /export\s+(?:\*|{[^}]+})\s+from\s+['"]([^'"]+)['"]/g;
|
|
1495
|
+
while ((match = exportRegex.exec(source)) !== null) {
|
|
1496
|
+
paths.push(match[1]);
|
|
1497
|
+
}
|
|
1498
|
+
const requireRegex = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
1499
|
+
while ((match = requireRegex.exec(source)) !== null) {
|
|
1500
|
+
paths.push(match[1]);
|
|
1501
|
+
}
|
|
1502
|
+
const dynamicRegex = /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
1503
|
+
while ((match = dynamicRegex.exec(source)) !== null) {
|
|
1504
|
+
paths.push(match[1]);
|
|
1505
|
+
}
|
|
1506
|
+
return [...new Set(paths)];
|
|
1507
|
+
}
|
|
1508
|
+
function resolveImportPath(importPath, fromDir) {
|
|
1509
|
+
const extensions = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
1510
|
+
for (const ext of extensions) {
|
|
1511
|
+
const fullPath = join2(fromDir, importPath + ext);
|
|
1512
|
+
if (existsSync2(fullPath)) {
|
|
1513
|
+
return fullPath;
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
for (const ext of extensions) {
|
|
1517
|
+
const indexPath = join2(fromDir, importPath, `index${ext}`);
|
|
1518
|
+
if (existsSync2(indexPath)) {
|
|
1519
|
+
return indexPath;
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
return void 0;
|
|
1523
|
+
}
|
|
1524
|
+
function sortedObject(obj) {
|
|
1525
|
+
const sorted = {};
|
|
1526
|
+
const keys = Object.keys(obj).sort();
|
|
1527
|
+
for (const key of keys) {
|
|
1528
|
+
const value = obj[key];
|
|
1529
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
1530
|
+
sorted[key] = sortedObject(value);
|
|
1531
|
+
} else {
|
|
1532
|
+
sorted[key] = value;
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
return sorted;
|
|
1536
|
+
}
|
|
1537
|
+
function generateBuildId() {
|
|
1538
|
+
const timestamp = Date.now().toString(36);
|
|
1539
|
+
const random = Math.random().toString(36).substring(2, 10);
|
|
1540
|
+
return `${timestamp}-${random}`;
|
|
1541
|
+
}
|
|
1542
|
+
function buildIdFromHash(hash) {
|
|
1543
|
+
return hash.substring(0, 12);
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
// libs/uipack/src/bundler/file-cache/component-builder.ts
|
|
1547
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
1548
|
+
import { existsSync as existsSync3 } from "fs";
|
|
1549
|
+
import { resolve as resolve2, extname } from "path";
|
|
1550
|
+
import { randomUUID } from "crypto";
|
|
1551
|
+
|
|
1552
|
+
// libs/uipack/src/dependency/cdn-registry.ts
|
|
1553
|
+
var DEFAULT_CDN_REGISTRY = {
|
|
1554
|
+
// ============================================
|
|
1555
|
+
// React Ecosystem
|
|
1556
|
+
// ============================================
|
|
1557
|
+
react: {
|
|
1558
|
+
packageName: "react",
|
|
1559
|
+
defaultVersion: "18.3.1",
|
|
1560
|
+
providers: {
|
|
1561
|
+
cloudflare: {
|
|
1562
|
+
url: "https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js",
|
|
1563
|
+
integrity: "sha512-Qp8J4Xr8LBZ5CXNJQc/HmLqFrpXz6lNkbzMYkYHKzQx5p1q1yOqPQHntXKoYgPPE/n9m0QF1OkJdXa2ePpO4fw==",
|
|
1564
|
+
global: "React",
|
|
1565
|
+
crossorigin: "anonymous"
|
|
1566
|
+
},
|
|
1567
|
+
jsdelivr: {
|
|
1568
|
+
url: "https://cdn.jsdelivr.net/npm/react@18.3.1/umd/react.production.min.js",
|
|
1569
|
+
global: "React",
|
|
1570
|
+
crossorigin: "anonymous"
|
|
1571
|
+
},
|
|
1572
|
+
unpkg: {
|
|
1573
|
+
url: "https://unpkg.com/react@18.3.1/umd/react.production.min.js",
|
|
1574
|
+
global: "React",
|
|
1575
|
+
crossorigin: "anonymous"
|
|
1576
|
+
},
|
|
1577
|
+
"esm.sh": {
|
|
1578
|
+
url: "https://esm.sh/react@18.3.1",
|
|
1579
|
+
esm: true,
|
|
1580
|
+
crossorigin: "anonymous"
|
|
1581
|
+
}
|
|
1582
|
+
},
|
|
1583
|
+
preferredProviders: ["cloudflare", "jsdelivr", "unpkg", "esm.sh"],
|
|
1584
|
+
metadata: {
|
|
1585
|
+
description: "A JavaScript library for building user interfaces",
|
|
1586
|
+
homepage: "https://react.dev",
|
|
1587
|
+
license: "MIT"
|
|
1588
|
+
}
|
|
1589
|
+
},
|
|
1590
|
+
"react-dom": {
|
|
1591
|
+
packageName: "react-dom",
|
|
1592
|
+
defaultVersion: "18.3.1",
|
|
1593
|
+
providers: {
|
|
1594
|
+
cloudflare: {
|
|
1595
|
+
url: "https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js",
|
|
1596
|
+
integrity: "sha512-6s2gVRdS3aT+FDdZTRJSzKlzIPqDXWyYl/5hPQb6hSgzKPGFcQyZhbqjbWVxGrs2dYNrINFXb0k0UD3d+CKPJA==",
|
|
1597
|
+
global: "ReactDOM",
|
|
1598
|
+
crossorigin: "anonymous",
|
|
1599
|
+
peerDependencies: ["react"]
|
|
1600
|
+
},
|
|
1601
|
+
jsdelivr: {
|
|
1602
|
+
url: "https://cdn.jsdelivr.net/npm/react-dom@18.3.1/umd/react-dom.production.min.js",
|
|
1603
|
+
global: "ReactDOM",
|
|
1604
|
+
crossorigin: "anonymous",
|
|
1605
|
+
peerDependencies: ["react"]
|
|
1606
|
+
},
|
|
1607
|
+
unpkg: {
|
|
1608
|
+
url: "https://unpkg.com/react-dom@18.3.1/umd/react-dom.production.min.js",
|
|
1609
|
+
global: "ReactDOM",
|
|
1610
|
+
crossorigin: "anonymous",
|
|
1611
|
+
peerDependencies: ["react"]
|
|
1612
|
+
},
|
|
1613
|
+
"esm.sh": {
|
|
1614
|
+
url: "https://esm.sh/react-dom@18.3.1",
|
|
1615
|
+
esm: true,
|
|
1616
|
+
crossorigin: "anonymous",
|
|
1617
|
+
peerDependencies: ["react"]
|
|
1618
|
+
}
|
|
1619
|
+
},
|
|
1620
|
+
preferredProviders: ["cloudflare", "jsdelivr", "unpkg", "esm.sh"],
|
|
1621
|
+
metadata: {
|
|
1622
|
+
description: "React package for working with the DOM",
|
|
1623
|
+
homepage: "https://react.dev",
|
|
1624
|
+
license: "MIT"
|
|
1625
|
+
}
|
|
1626
|
+
},
|
|
1627
|
+
// ============================================
|
|
1628
|
+
// Charting Libraries
|
|
1629
|
+
// ============================================
|
|
1630
|
+
"chart.js": {
|
|
1631
|
+
packageName: "chart.js",
|
|
1632
|
+
defaultVersion: "4.4.7",
|
|
1633
|
+
providers: {
|
|
1634
|
+
cloudflare: {
|
|
1635
|
+
url: "https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.7/chart.umd.min.js",
|
|
1636
|
+
integrity: "sha512-dMDjIoZjJD6gs0KPBhFYjLQrH3kIohSEn6HzWs6Y6GiO0+L9kk/bM3cR5KNEDK1KvMNpTIZG6pHK9SZfCJHRpQ==",
|
|
1637
|
+
global: "Chart",
|
|
1638
|
+
crossorigin: "anonymous"
|
|
1639
|
+
},
|
|
1640
|
+
jsdelivr: {
|
|
1641
|
+
url: "https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js",
|
|
1642
|
+
global: "Chart",
|
|
1643
|
+
crossorigin: "anonymous"
|
|
1644
|
+
},
|
|
1645
|
+
unpkg: {
|
|
1646
|
+
url: "https://unpkg.com/chart.js@4.4.7/dist/chart.umd.min.js",
|
|
1647
|
+
global: "Chart",
|
|
1648
|
+
crossorigin: "anonymous"
|
|
1649
|
+
}
|
|
1650
|
+
},
|
|
1651
|
+
preferredProviders: ["cloudflare", "jsdelivr", "unpkg"],
|
|
1652
|
+
metadata: {
|
|
1653
|
+
description: "Simple yet flexible JavaScript charting library",
|
|
1654
|
+
homepage: "https://www.chartjs.org",
|
|
1655
|
+
license: "MIT"
|
|
1656
|
+
}
|
|
1657
|
+
},
|
|
1658
|
+
"react-chartjs-2": {
|
|
1659
|
+
packageName: "react-chartjs-2",
|
|
1660
|
+
defaultVersion: "5.3.0",
|
|
1661
|
+
providers: {
|
|
1662
|
+
cloudflare: {
|
|
1663
|
+
url: "https://cdnjs.cloudflare.com/ajax/libs/react-chartjs-2/5.3.0/react-chartjs-2.min.js",
|
|
1664
|
+
global: "ReactChartjs2",
|
|
1665
|
+
crossorigin: "anonymous",
|
|
1666
|
+
peerDependencies: ["react", "chart.js"]
|
|
1667
|
+
},
|
|
1668
|
+
jsdelivr: {
|
|
1669
|
+
url: "https://cdn.jsdelivr.net/npm/react-chartjs-2@5.3.0/dist/index.umd.js",
|
|
1670
|
+
global: "ReactChartjs2",
|
|
1671
|
+
crossorigin: "anonymous",
|
|
1672
|
+
peerDependencies: ["react", "chart.js"]
|
|
1673
|
+
},
|
|
1674
|
+
"esm.sh": {
|
|
1675
|
+
url: "https://esm.sh/react-chartjs-2@5.3.0",
|
|
1676
|
+
esm: true,
|
|
1677
|
+
crossorigin: "anonymous",
|
|
1678
|
+
peerDependencies: ["react", "chart.js"]
|
|
1679
|
+
}
|
|
1680
|
+
},
|
|
1681
|
+
preferredProviders: ["cloudflare", "jsdelivr", "esm.sh"],
|
|
1682
|
+
metadata: {
|
|
1683
|
+
description: "React components for Chart.js",
|
|
1684
|
+
homepage: "https://react-chartjs-2.js.org",
|
|
1685
|
+
license: "MIT"
|
|
1686
|
+
}
|
|
1687
|
+
},
|
|
1688
|
+
// ============================================
|
|
1689
|
+
// D3.js
|
|
1690
|
+
// ============================================
|
|
1691
|
+
d3: {
|
|
1692
|
+
packageName: "d3",
|
|
1693
|
+
defaultVersion: "7.9.0",
|
|
1694
|
+
providers: {
|
|
1695
|
+
cloudflare: {
|
|
1696
|
+
url: "https://cdnjs.cloudflare.com/ajax/libs/d3/7.9.0/d3.min.js",
|
|
1697
|
+
integrity: "sha512-vc58qvvBdrDR4etbxMdlTt4GBQk1qjvyORR2nrsPsFPyrs+/u5c3+1Ct6upOgdZoIl7eq6k3a1UPDSNAQi/32A==",
|
|
1698
|
+
global: "d3",
|
|
1699
|
+
crossorigin: "anonymous"
|
|
1700
|
+
},
|
|
1701
|
+
jsdelivr: {
|
|
1702
|
+
url: "https://cdn.jsdelivr.net/npm/d3@7.9.0/dist/d3.min.js",
|
|
1703
|
+
global: "d3",
|
|
1704
|
+
crossorigin: "anonymous"
|
|
1705
|
+
},
|
|
1706
|
+
unpkg: {
|
|
1707
|
+
url: "https://unpkg.com/d3@7.9.0/dist/d3.min.js",
|
|
1708
|
+
global: "d3",
|
|
1709
|
+
crossorigin: "anonymous"
|
|
1710
|
+
}
|
|
1711
|
+
},
|
|
1712
|
+
preferredProviders: ["cloudflare", "jsdelivr", "unpkg"],
|
|
1713
|
+
metadata: {
|
|
1714
|
+
description: "Data-Driven Documents",
|
|
1715
|
+
homepage: "https://d3js.org",
|
|
1716
|
+
license: "ISC"
|
|
1717
|
+
}
|
|
1718
|
+
},
|
|
1719
|
+
// ============================================
|
|
1720
|
+
// Utility Libraries
|
|
1721
|
+
// ============================================
|
|
1722
|
+
lodash: {
|
|
1723
|
+
packageName: "lodash",
|
|
1724
|
+
defaultVersion: "4.17.21",
|
|
1725
|
+
providers: {
|
|
1726
|
+
cloudflare: {
|
|
1727
|
+
url: "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js",
|
|
1728
|
+
integrity: "sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==",
|
|
1729
|
+
global: "_",
|
|
1730
|
+
crossorigin: "anonymous"
|
|
1731
|
+
},
|
|
1732
|
+
jsdelivr: {
|
|
1733
|
+
url: "https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js",
|
|
1734
|
+
global: "_",
|
|
1735
|
+
crossorigin: "anonymous"
|
|
1736
|
+
},
|
|
1737
|
+
unpkg: {
|
|
1738
|
+
url: "https://unpkg.com/lodash@4.17.21/lodash.min.js",
|
|
1739
|
+
global: "_",
|
|
1740
|
+
crossorigin: "anonymous"
|
|
1741
|
+
}
|
|
1742
|
+
},
|
|
1743
|
+
preferredProviders: ["cloudflare", "jsdelivr", "unpkg"],
|
|
1744
|
+
metadata: {
|
|
1745
|
+
description: "A modern JavaScript utility library",
|
|
1746
|
+
homepage: "https://lodash.com",
|
|
1747
|
+
license: "MIT"
|
|
1748
|
+
}
|
|
1749
|
+
},
|
|
1750
|
+
"lodash-es": {
|
|
1751
|
+
packageName: "lodash-es",
|
|
1752
|
+
defaultVersion: "4.17.21",
|
|
1753
|
+
providers: {
|
|
1754
|
+
"esm.sh": {
|
|
1755
|
+
url: "https://esm.sh/lodash-es@4.17.21",
|
|
1756
|
+
esm: true,
|
|
1757
|
+
crossorigin: "anonymous"
|
|
1758
|
+
},
|
|
1759
|
+
jsdelivr: {
|
|
1760
|
+
url: "https://cdn.jsdelivr.net/npm/lodash-es@4.17.21/+esm",
|
|
1761
|
+
esm: true,
|
|
1762
|
+
crossorigin: "anonymous"
|
|
1763
|
+
}
|
|
1764
|
+
},
|
|
1765
|
+
preferredProviders: ["esm.sh", "jsdelivr"],
|
|
1766
|
+
metadata: {
|
|
1767
|
+
description: "Lodash exported as ES modules",
|
|
1768
|
+
homepage: "https://lodash.com",
|
|
1769
|
+
license: "MIT"
|
|
1770
|
+
}
|
|
1771
|
+
},
|
|
1772
|
+
dayjs: {
|
|
1773
|
+
packageName: "dayjs",
|
|
1774
|
+
defaultVersion: "1.11.13",
|
|
1775
|
+
providers: {
|
|
1776
|
+
cloudflare: {
|
|
1777
|
+
url: "https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.11.13/dayjs.min.js",
|
|
1778
|
+
integrity: "sha512-Ot7ArUEhJDU0cwoBNNnWe487kjL5wAOsIYig8llY/l0P2TUFwgsAHVmrZMHsT8NGo+HwkjTJsNErS6QqIkBxDw==",
|
|
1779
|
+
global: "dayjs",
|
|
1780
|
+
crossorigin: "anonymous"
|
|
1781
|
+
},
|
|
1782
|
+
jsdelivr: {
|
|
1783
|
+
url: "https://cdn.jsdelivr.net/npm/dayjs@1.11.13/dayjs.min.js",
|
|
1784
|
+
global: "dayjs",
|
|
1785
|
+
crossorigin: "anonymous"
|
|
1786
|
+
},
|
|
1787
|
+
unpkg: {
|
|
1788
|
+
url: "https://unpkg.com/dayjs@1.11.13/dayjs.min.js",
|
|
1789
|
+
global: "dayjs",
|
|
1790
|
+
crossorigin: "anonymous"
|
|
1791
|
+
}
|
|
1792
|
+
},
|
|
1793
|
+
preferredProviders: ["cloudflare", "jsdelivr", "unpkg"],
|
|
1794
|
+
metadata: {
|
|
1795
|
+
description: "Fast 2kB alternative to Moment.js with the same modern API",
|
|
1796
|
+
homepage: "https://day.js.org",
|
|
1797
|
+
license: "MIT"
|
|
1798
|
+
}
|
|
1799
|
+
},
|
|
1800
|
+
"date-fns": {
|
|
1801
|
+
packageName: "date-fns",
|
|
1802
|
+
defaultVersion: "4.1.0",
|
|
1803
|
+
providers: {
|
|
1804
|
+
"esm.sh": {
|
|
1805
|
+
url: "https://esm.sh/date-fns@4.1.0",
|
|
1806
|
+
esm: true,
|
|
1807
|
+
crossorigin: "anonymous"
|
|
1808
|
+
},
|
|
1809
|
+
jsdelivr: {
|
|
1810
|
+
url: "https://cdn.jsdelivr.net/npm/date-fns@4.1.0/+esm",
|
|
1811
|
+
esm: true,
|
|
1812
|
+
crossorigin: "anonymous"
|
|
1813
|
+
}
|
|
1814
|
+
},
|
|
1815
|
+
preferredProviders: ["esm.sh", "jsdelivr"],
|
|
1816
|
+
metadata: {
|
|
1817
|
+
description: "Modern JavaScript date utility library",
|
|
1818
|
+
homepage: "https://date-fns.org",
|
|
1819
|
+
license: "MIT"
|
|
1820
|
+
}
|
|
1821
|
+
},
|
|
1822
|
+
// ============================================
|
|
1823
|
+
// Animation Libraries
|
|
1824
|
+
// ============================================
|
|
1825
|
+
"framer-motion": {
|
|
1826
|
+
packageName: "framer-motion",
|
|
1827
|
+
defaultVersion: "11.15.0",
|
|
1828
|
+
providers: {
|
|
1829
|
+
"esm.sh": {
|
|
1830
|
+
url: "https://esm.sh/framer-motion@11.15.0",
|
|
1831
|
+
esm: true,
|
|
1832
|
+
crossorigin: "anonymous",
|
|
1833
|
+
peerDependencies: ["react", "react-dom"]
|
|
1834
|
+
},
|
|
1835
|
+
jsdelivr: {
|
|
1836
|
+
url: "https://cdn.jsdelivr.net/npm/framer-motion@11.15.0/dist/framer-motion.js",
|
|
1837
|
+
global: "Motion",
|
|
1838
|
+
crossorigin: "anonymous",
|
|
1839
|
+
peerDependencies: ["react", "react-dom"]
|
|
1840
|
+
}
|
|
1841
|
+
},
|
|
1842
|
+
preferredProviders: ["esm.sh", "jsdelivr"],
|
|
1843
|
+
metadata: {
|
|
1844
|
+
description: "Production-ready motion library for React",
|
|
1845
|
+
homepage: "https://www.framer.com/motion/",
|
|
1846
|
+
license: "MIT"
|
|
1847
|
+
}
|
|
1848
|
+
},
|
|
1849
|
+
// ============================================
|
|
1850
|
+
// UI Component Libraries
|
|
1851
|
+
// ============================================
|
|
1852
|
+
"lucide-react": {
|
|
1853
|
+
packageName: "lucide-react",
|
|
1854
|
+
defaultVersion: "0.468.0",
|
|
1855
|
+
providers: {
|
|
1856
|
+
"esm.sh": {
|
|
1857
|
+
url: "https://esm.sh/lucide-react@0.468.0",
|
|
1858
|
+
esm: true,
|
|
1859
|
+
crossorigin: "anonymous",
|
|
1860
|
+
peerDependencies: ["react"]
|
|
1861
|
+
},
|
|
1862
|
+
jsdelivr: {
|
|
1863
|
+
url: "https://cdn.jsdelivr.net/npm/lucide-react@0.468.0/dist/esm/lucide-react.js",
|
|
1864
|
+
esm: true,
|
|
1865
|
+
crossorigin: "anonymous",
|
|
1866
|
+
peerDependencies: ["react"]
|
|
1867
|
+
}
|
|
1868
|
+
},
|
|
1869
|
+
preferredProviders: ["esm.sh", "jsdelivr"],
|
|
1870
|
+
metadata: {
|
|
1871
|
+
description: "Beautiful & consistent icon toolkit for React",
|
|
1872
|
+
homepage: "https://lucide.dev",
|
|
1873
|
+
license: "ISC"
|
|
1874
|
+
}
|
|
1875
|
+
},
|
|
1876
|
+
// ============================================
|
|
1877
|
+
// Markdown/Syntax Highlighting
|
|
1878
|
+
// ============================================
|
|
1879
|
+
marked: {
|
|
1880
|
+
packageName: "marked",
|
|
1881
|
+
defaultVersion: "15.0.4",
|
|
1882
|
+
providers: {
|
|
1883
|
+
cloudflare: {
|
|
1884
|
+
url: "https://cdnjs.cloudflare.com/ajax/libs/marked/15.0.4/marked.min.js",
|
|
1885
|
+
integrity: "sha512-Rn/d0sGeizGbk3VJEiYNDt/mMcfuzYoFkia3iBffv+HX8VUrHMo/0cKjZuxWGoZLPh/VxUcC9ais+RBFZW9EBg==",
|
|
1886
|
+
global: "marked",
|
|
1887
|
+
crossorigin: "anonymous"
|
|
1888
|
+
},
|
|
1889
|
+
jsdelivr: {
|
|
1890
|
+
url: "https://cdn.jsdelivr.net/npm/marked@15.0.4/marked.min.js",
|
|
1891
|
+
global: "marked",
|
|
1892
|
+
crossorigin: "anonymous"
|
|
1893
|
+
},
|
|
1894
|
+
unpkg: {
|
|
1895
|
+
url: "https://unpkg.com/marked@15.0.4/marked.min.js",
|
|
1896
|
+
global: "marked",
|
|
1897
|
+
crossorigin: "anonymous"
|
|
1898
|
+
}
|
|
1899
|
+
},
|
|
1900
|
+
preferredProviders: ["cloudflare", "jsdelivr", "unpkg"],
|
|
1901
|
+
metadata: {
|
|
1902
|
+
description: "A markdown parser and compiler",
|
|
1903
|
+
homepage: "https://marked.js.org",
|
|
1904
|
+
license: "MIT"
|
|
1905
|
+
}
|
|
1906
|
+
},
|
|
1907
|
+
"highlight.js": {
|
|
1908
|
+
packageName: "highlight.js",
|
|
1909
|
+
defaultVersion: "11.10.0",
|
|
1910
|
+
providers: {
|
|
1911
|
+
cloudflare: {
|
|
1912
|
+
url: "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.10.0/highlight.min.js",
|
|
1913
|
+
integrity: "sha512-6yoqbrcLAHDWAdQmiRlHG4+m0g/CT/V9AGyxabG8j7Jk8j3v3k6mIP1iN/PvSofcWet2tf8SRn/j3L/+pb7LRQ==",
|
|
1914
|
+
global: "hljs",
|
|
1915
|
+
crossorigin: "anonymous"
|
|
1916
|
+
},
|
|
1917
|
+
jsdelivr: {
|
|
1918
|
+
url: "https://cdn.jsdelivr.net/npm/highlight.js@11.10.0/lib/core.min.js",
|
|
1919
|
+
global: "hljs",
|
|
1920
|
+
crossorigin: "anonymous"
|
|
1921
|
+
},
|
|
1922
|
+
unpkg: {
|
|
1923
|
+
url: "https://unpkg.com/highlight.js@11.10.0/lib/core.min.js",
|
|
1924
|
+
global: "hljs",
|
|
1925
|
+
crossorigin: "anonymous"
|
|
1926
|
+
}
|
|
1927
|
+
},
|
|
1928
|
+
preferredProviders: ["cloudflare", "jsdelivr", "unpkg"],
|
|
1929
|
+
metadata: {
|
|
1930
|
+
description: "Syntax highlighting for the web",
|
|
1931
|
+
homepage: "https://highlightjs.org",
|
|
1932
|
+
license: "BSD-3-Clause"
|
|
1933
|
+
}
|
|
1934
|
+
},
|
|
1935
|
+
// ============================================
|
|
1936
|
+
// Interactive Libraries
|
|
1937
|
+
// ============================================
|
|
1938
|
+
"htmx.org": {
|
|
1939
|
+
packageName: "htmx.org",
|
|
1940
|
+
defaultVersion: "2.0.4",
|
|
1941
|
+
providers: {
|
|
1942
|
+
cloudflare: {
|
|
1943
|
+
url: "https://cdnjs.cloudflare.com/ajax/libs/htmx/2.0.4/htmx.min.js",
|
|
1944
|
+
integrity: "sha512-2kIcAizYXhIn5IyXrMC72f2nh0JAtESHRpOieVw5dYPYeHwLCC2eKCqvdZDYRSEgasKrPpEPpRFjL8gqwBZWAA==",
|
|
1945
|
+
global: "htmx",
|
|
1946
|
+
crossorigin: "anonymous"
|
|
1947
|
+
},
|
|
1948
|
+
jsdelivr: {
|
|
1949
|
+
url: "https://cdn.jsdelivr.net/npm/htmx.org@2.0.4/dist/htmx.min.js",
|
|
1950
|
+
global: "htmx",
|
|
1951
|
+
crossorigin: "anonymous"
|
|
1952
|
+
},
|
|
1953
|
+
unpkg: {
|
|
1954
|
+
url: "https://unpkg.com/htmx.org@2.0.4/dist/htmx.min.js",
|
|
1955
|
+
global: "htmx",
|
|
1956
|
+
crossorigin: "anonymous"
|
|
1957
|
+
}
|
|
1958
|
+
},
|
|
1959
|
+
preferredProviders: ["cloudflare", "jsdelivr", "unpkg"],
|
|
1960
|
+
metadata: {
|
|
1961
|
+
description: "High power tools for HTML",
|
|
1962
|
+
homepage: "https://htmx.org",
|
|
1963
|
+
license: "BSD-2-Clause"
|
|
1964
|
+
}
|
|
1965
|
+
},
|
|
1966
|
+
alpinejs: {
|
|
1967
|
+
packageName: "alpinejs",
|
|
1968
|
+
defaultVersion: "3.14.3",
|
|
1969
|
+
providers: {
|
|
1970
|
+
cloudflare: {
|
|
1971
|
+
url: "https://cdnjs.cloudflare.com/ajax/libs/alpinejs/3.14.3/cdn.min.js",
|
|
1972
|
+
integrity: "sha512-lrQ8FHgsWKFSuQFq8NKPJicjlvJFEIrCqEj8zeX7ZOUlHWltN/Iow4jND+x84jqTdDf9n+hvQpJjGDvOl/eDRA==",
|
|
1973
|
+
global: "Alpine",
|
|
1974
|
+
crossorigin: "anonymous"
|
|
1975
|
+
},
|
|
1976
|
+
jsdelivr: {
|
|
1977
|
+
url: "https://cdn.jsdelivr.net/npm/alpinejs@3.14.3/dist/cdn.min.js",
|
|
1978
|
+
global: "Alpine",
|
|
1979
|
+
crossorigin: "anonymous"
|
|
1980
|
+
},
|
|
1981
|
+
unpkg: {
|
|
1982
|
+
url: "https://unpkg.com/alpinejs@3.14.3/dist/cdn.min.js",
|
|
1983
|
+
global: "Alpine",
|
|
1984
|
+
crossorigin: "anonymous"
|
|
1985
|
+
}
|
|
1986
|
+
},
|
|
1987
|
+
preferredProviders: ["cloudflare", "jsdelivr", "unpkg"],
|
|
1988
|
+
metadata: {
|
|
1989
|
+
description: "A rugged, minimal framework for composing behavior directly in your markup",
|
|
1990
|
+
homepage: "https://alpinejs.dev",
|
|
1991
|
+
license: "MIT"
|
|
1992
|
+
}
|
|
1993
|
+
},
|
|
1994
|
+
// ============================================
|
|
1995
|
+
// Templating Libraries
|
|
1996
|
+
// ============================================
|
|
1997
|
+
handlebars: {
|
|
1998
|
+
packageName: "handlebars",
|
|
1999
|
+
defaultVersion: "4.7.8",
|
|
2000
|
+
providers: {
|
|
2001
|
+
cloudflare: {
|
|
2002
|
+
url: "https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.8/handlebars.min.js",
|
|
2003
|
+
integrity: "sha512-E1dSFxg+wsfJ4HKjutk/WaCzK7S2wv1POn1RRPGh8ZK+ag9l244Vqxji3r6wgz9YBf6+vhQEYJZpSjqWFPg9gg==",
|
|
2004
|
+
global: "Handlebars",
|
|
2005
|
+
crossorigin: "anonymous"
|
|
2006
|
+
},
|
|
2007
|
+
jsdelivr: {
|
|
2008
|
+
url: "https://cdn.jsdelivr.net/npm/handlebars@4.7.8/dist/handlebars.min.js",
|
|
2009
|
+
global: "Handlebars",
|
|
2010
|
+
crossorigin: "anonymous"
|
|
2011
|
+
},
|
|
2012
|
+
unpkg: {
|
|
2013
|
+
url: "https://unpkg.com/handlebars@4.7.8/dist/handlebars.min.js",
|
|
2014
|
+
global: "Handlebars",
|
|
2015
|
+
crossorigin: "anonymous"
|
|
2016
|
+
}
|
|
2017
|
+
},
|
|
2018
|
+
preferredProviders: ["cloudflare", "jsdelivr", "unpkg"],
|
|
2019
|
+
metadata: {
|
|
2020
|
+
description: "Minimal templating on steroids",
|
|
2021
|
+
homepage: "https://handlebarsjs.com",
|
|
2022
|
+
license: "MIT"
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
};
|
|
2026
|
+
var CDN_PROVIDER_PRIORITY = {
|
|
2027
|
+
claude: ["cloudflare"],
|
|
2028
|
+
// ONLY cloudflare for Claude
|
|
2029
|
+
openai: ["cloudflare", "jsdelivr", "unpkg", "esm.sh"],
|
|
2030
|
+
cursor: ["cloudflare", "jsdelivr", "unpkg", "esm.sh"],
|
|
2031
|
+
gemini: ["cloudflare", "jsdelivr", "unpkg", "esm.sh"],
|
|
2032
|
+
continue: ["cloudflare", "jsdelivr", "unpkg", "esm.sh"],
|
|
2033
|
+
cody: ["cloudflare", "jsdelivr", "unpkg", "esm.sh"],
|
|
2034
|
+
unknown: ["cloudflare", "jsdelivr", "unpkg", "esm.sh"]
|
|
2035
|
+
// Default to cloudflare first
|
|
2036
|
+
};
|
|
2037
|
+
function lookupPackage(packageName, registry = DEFAULT_CDN_REGISTRY) {
|
|
2038
|
+
return registry[packageName];
|
|
2039
|
+
}
|
|
2040
|
+
function mergeRegistries(customRegistry) {
|
|
2041
|
+
return {
|
|
2042
|
+
...DEFAULT_CDN_REGISTRY,
|
|
2043
|
+
...customRegistry
|
|
2044
|
+
};
|
|
2045
|
+
}
|
|
2046
|
+
function getPackagePeerDependencies(packageName, registry = DEFAULT_CDN_REGISTRY) {
|
|
2047
|
+
const entry = lookupPackage(packageName, registry);
|
|
2048
|
+
if (!entry) return [];
|
|
2049
|
+
for (const provider of Object.keys(entry.providers)) {
|
|
2050
|
+
const config = entry.providers[provider];
|
|
2051
|
+
if (config?.peerDependencies) {
|
|
2052
|
+
return config.peerDependencies;
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
return [];
|
|
2056
|
+
}
|
|
2057
|
+
function resolveAllDependencies(packageNames, platform = "unknown", registry = DEFAULT_CDN_REGISTRY) {
|
|
2058
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
2059
|
+
const queue = [...packageNames];
|
|
2060
|
+
while (queue.length > 0) {
|
|
2061
|
+
const packageName = queue.shift();
|
|
2062
|
+
if (!packageName) continue;
|
|
2063
|
+
if (resolved.has(packageName)) continue;
|
|
2064
|
+
resolved.add(packageName);
|
|
2065
|
+
const peers = getPackagePeerDependencies(packageName, registry);
|
|
2066
|
+
for (const peer of peers) {
|
|
2067
|
+
if (!resolved.has(peer)) {
|
|
2068
|
+
queue.push(peer);
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
const result = [];
|
|
2073
|
+
const remaining = new Set(resolved);
|
|
2074
|
+
while (remaining.size > 0) {
|
|
2075
|
+
let added = false;
|
|
2076
|
+
for (const pkg of remaining) {
|
|
2077
|
+
const peers = getPackagePeerDependencies(pkg, registry);
|
|
2078
|
+
const allPeersResolved = peers.every((peer) => !remaining.has(peer) || result.includes(peer));
|
|
2079
|
+
if (allPeersResolved) {
|
|
2080
|
+
if (!result.includes(pkg)) {
|
|
2081
|
+
result.push(pkg);
|
|
2082
|
+
}
|
|
2083
|
+
remaining.delete(pkg);
|
|
2084
|
+
added = true;
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
if (!added && remaining.size > 0) {
|
|
2088
|
+
const next = remaining.values().next().value;
|
|
2089
|
+
if (next !== void 0) {
|
|
2090
|
+
if (!result.includes(next)) {
|
|
2091
|
+
result.push(next);
|
|
2092
|
+
}
|
|
2093
|
+
remaining.delete(next);
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
return result;
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
// libs/uipack/src/dependency/import-parser.ts
|
|
2101
|
+
var IMPORT_PATTERNS = {
|
|
2102
|
+
/**
|
|
2103
|
+
* Named imports: import { foo, bar } from 'module'
|
|
2104
|
+
* Also handles renamed imports: import { foo as f } from 'module'
|
|
2105
|
+
*/
|
|
2106
|
+
named: /import\s*\{([^}]+)\}\s*from\s*['"]([^'"]+)['"]/g,
|
|
2107
|
+
/**
|
|
2108
|
+
* Default imports: import foo from 'module'
|
|
2109
|
+
*/
|
|
2110
|
+
default: /import\s+(\w+)\s+from\s*['"]([^'"]+)['"]/g,
|
|
2111
|
+
/**
|
|
2112
|
+
* Namespace imports: import * as foo from 'module'
|
|
2113
|
+
*/
|
|
2114
|
+
namespace: /import\s*\*\s*as\s+(\w+)\s+from\s*['"]([^'"]+)['"]/g,
|
|
2115
|
+
/**
|
|
2116
|
+
* Side-effect imports: import 'module'
|
|
2117
|
+
*/
|
|
2118
|
+
sideEffect: /import\s*['"]([^'"]+)['"]/g,
|
|
2119
|
+
/**
|
|
2120
|
+
* Dynamic imports: import('module') or await import('module')
|
|
2121
|
+
*/
|
|
2122
|
+
dynamic: /(?:await\s+)?import\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
2123
|
+
/**
|
|
2124
|
+
* Combined default and named: import foo, { bar } from 'module'
|
|
2125
|
+
*/
|
|
2126
|
+
defaultAndNamed: /import\s+(\w+)\s*,\s*\{([^}]+)\}\s*from\s*['"]([^'"]+)['"]/g,
|
|
2127
|
+
/**
|
|
2128
|
+
* Combined default and namespace: import foo, * as bar from 'module'
|
|
2129
|
+
*/
|
|
2130
|
+
defaultAndNamespace: /import\s+(\w+)\s*,\s*\*\s*as\s+(\w+)\s+from\s*['"]([^'"]+)['"]/g,
|
|
2131
|
+
/**
|
|
2132
|
+
* Re-exports: export { foo } from 'module'
|
|
2133
|
+
*/
|
|
2134
|
+
reExport: /export\s*\{[^}]+\}\s*from\s*['"]([^'"]+)['"]/g,
|
|
2135
|
+
/**
|
|
2136
|
+
* Re-export all: export * from 'module'
|
|
2137
|
+
*/
|
|
2138
|
+
reExportAll: /export\s*\*\s*from\s*['"]([^'"]+)['"]/g
|
|
2139
|
+
};
|
|
2140
|
+
function parseNamedImports(namedString) {
|
|
2141
|
+
return namedString.split(",").map((s) => s.trim()).filter((s) => s.length > 0).map((s) => {
|
|
2142
|
+
const asMatch = s.match(/^(\w+)\s+as\s+\w+$/);
|
|
2143
|
+
return asMatch ? asMatch[1] : s;
|
|
2144
|
+
});
|
|
2145
|
+
}
|
|
2146
|
+
function isRelativeImport(specifier) {
|
|
2147
|
+
return specifier.startsWith("./") || specifier.startsWith("../") || specifier.startsWith("/");
|
|
2148
|
+
}
|
|
2149
|
+
function isExternalImport(specifier) {
|
|
2150
|
+
return !isRelativeImport(specifier) && !specifier.startsWith("#");
|
|
2151
|
+
}
|
|
2152
|
+
function getPackageName(specifier) {
|
|
2153
|
+
if (specifier.startsWith("@")) {
|
|
2154
|
+
const parts = specifier.split("/");
|
|
2155
|
+
if (parts.length >= 2) {
|
|
2156
|
+
return `${parts[0]}/${parts[1]}`;
|
|
2157
|
+
}
|
|
2158
|
+
return specifier;
|
|
2159
|
+
}
|
|
2160
|
+
const firstSlash = specifier.indexOf("/");
|
|
2161
|
+
return firstSlash === -1 ? specifier : specifier.slice(0, firstSlash);
|
|
2162
|
+
}
|
|
2163
|
+
function getLineNumber(source, index) {
|
|
2164
|
+
let line = 1;
|
|
2165
|
+
for (let i = 0; i < index && i < source.length; i++) {
|
|
2166
|
+
if (source[i] === "\n") {
|
|
2167
|
+
line++;
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
return line;
|
|
2171
|
+
}
|
|
2172
|
+
function getColumnNumber(source, index) {
|
|
2173
|
+
let column = 0;
|
|
2174
|
+
for (let i = index - 1; i >= 0 && source[i] !== "\n"; i--) {
|
|
2175
|
+
column++;
|
|
2176
|
+
}
|
|
2177
|
+
return column;
|
|
2178
|
+
}
|
|
2179
|
+
function parseImports(source) {
|
|
2180
|
+
const imports = [];
|
|
2181
|
+
const seenStatements = /* @__PURE__ */ new Set();
|
|
2182
|
+
const addImport = (imp) => {
|
|
2183
|
+
const key = `${imp.type}:${imp.specifier}:${imp.statement}`;
|
|
2184
|
+
if (!seenStatements.has(key)) {
|
|
2185
|
+
seenStatements.add(key);
|
|
2186
|
+
imports.push(imp);
|
|
2187
|
+
}
|
|
2188
|
+
};
|
|
2189
|
+
let match;
|
|
2190
|
+
const defaultAndNamedRegex = new RegExp(IMPORT_PATTERNS.defaultAndNamed.source, "g");
|
|
2191
|
+
while ((match = defaultAndNamedRegex.exec(source)) !== null) {
|
|
2192
|
+
const [statement, defaultName, namedString, specifier] = match;
|
|
2193
|
+
const namedImports = parseNamedImports(namedString);
|
|
2194
|
+
addImport({
|
|
2195
|
+
statement,
|
|
2196
|
+
specifier,
|
|
2197
|
+
type: "default",
|
|
2198
|
+
defaultImport: defaultName,
|
|
2199
|
+
namedImports,
|
|
2200
|
+
line: getLineNumber(source, match.index),
|
|
2201
|
+
column: getColumnNumber(source, match.index)
|
|
2202
|
+
});
|
|
2203
|
+
}
|
|
2204
|
+
const defaultAndNamespaceRegex = new RegExp(IMPORT_PATTERNS.defaultAndNamespace.source, "g");
|
|
2205
|
+
while ((match = defaultAndNamespaceRegex.exec(source)) !== null) {
|
|
2206
|
+
const [statement, defaultName, namespaceName, specifier] = match;
|
|
2207
|
+
addImport({
|
|
2208
|
+
statement,
|
|
2209
|
+
specifier,
|
|
2210
|
+
type: "default",
|
|
2211
|
+
defaultImport: defaultName,
|
|
2212
|
+
namespaceImport: namespaceName,
|
|
2213
|
+
line: getLineNumber(source, match.index),
|
|
2214
|
+
column: getColumnNumber(source, match.index)
|
|
2215
|
+
});
|
|
2216
|
+
}
|
|
2217
|
+
const namedRegex = new RegExp(IMPORT_PATTERNS.named.source, "g");
|
|
2218
|
+
while ((match = namedRegex.exec(source)) !== null) {
|
|
2219
|
+
const [statement, namedString, specifier] = match;
|
|
2220
|
+
const namedImports = parseNamedImports(namedString);
|
|
2221
|
+
addImport({
|
|
2222
|
+
statement,
|
|
2223
|
+
specifier,
|
|
2224
|
+
type: "named",
|
|
2225
|
+
namedImports,
|
|
2226
|
+
line: getLineNumber(source, match.index),
|
|
2227
|
+
column: getColumnNumber(source, match.index)
|
|
2228
|
+
});
|
|
2229
|
+
}
|
|
2230
|
+
const defaultRegex = new RegExp(IMPORT_PATTERNS.default.source, "g");
|
|
2231
|
+
while ((match = defaultRegex.exec(source)) !== null) {
|
|
2232
|
+
const [statement, defaultName, specifier] = match;
|
|
2233
|
+
const afterMatch = source.slice(match.index + match[0].length - specifier.length - 2);
|
|
2234
|
+
if (afterMatch.startsWith(",")) continue;
|
|
2235
|
+
addImport({
|
|
2236
|
+
statement,
|
|
2237
|
+
specifier,
|
|
2238
|
+
type: "default",
|
|
2239
|
+
defaultImport: defaultName,
|
|
2240
|
+
line: getLineNumber(source, match.index),
|
|
2241
|
+
column: getColumnNumber(source, match.index)
|
|
2242
|
+
});
|
|
2243
|
+
}
|
|
2244
|
+
const namespaceRegex = new RegExp(IMPORT_PATTERNS.namespace.source, "g");
|
|
2245
|
+
while ((match = namespaceRegex.exec(source)) !== null) {
|
|
2246
|
+
const [statement, namespaceName, specifier] = match;
|
|
2247
|
+
addImport({
|
|
2248
|
+
statement,
|
|
2249
|
+
specifier,
|
|
2250
|
+
type: "namespace",
|
|
2251
|
+
namespaceImport: namespaceName,
|
|
2252
|
+
line: getLineNumber(source, match.index),
|
|
2253
|
+
column: getColumnNumber(source, match.index)
|
|
2254
|
+
});
|
|
2255
|
+
}
|
|
2256
|
+
const sideEffectRegex = new RegExp(IMPORT_PATTERNS.sideEffect.source, "g");
|
|
2257
|
+
while ((match = sideEffectRegex.exec(source)) !== null) {
|
|
2258
|
+
const [statement, specifier] = match;
|
|
2259
|
+
const beforeMatch = source.slice(Math.max(0, match.index - 50), match.index);
|
|
2260
|
+
if (beforeMatch.includes("from")) continue;
|
|
2261
|
+
addImport({
|
|
2262
|
+
statement,
|
|
2263
|
+
specifier,
|
|
2264
|
+
type: "side-effect",
|
|
2265
|
+
line: getLineNumber(source, match.index),
|
|
2266
|
+
column: getColumnNumber(source, match.index)
|
|
2267
|
+
});
|
|
2268
|
+
}
|
|
2269
|
+
const dynamicRegex = new RegExp(IMPORT_PATTERNS.dynamic.source, "g");
|
|
2270
|
+
while ((match = dynamicRegex.exec(source)) !== null) {
|
|
2271
|
+
const [statement, specifier] = match;
|
|
2272
|
+
addImport({
|
|
2273
|
+
statement,
|
|
2274
|
+
specifier,
|
|
2275
|
+
type: "dynamic",
|
|
2276
|
+
line: getLineNumber(source, match.index),
|
|
2277
|
+
column: getColumnNumber(source, match.index)
|
|
2278
|
+
});
|
|
2279
|
+
}
|
|
2280
|
+
const reExportRegex = new RegExp(IMPORT_PATTERNS.reExport.source, "g");
|
|
2281
|
+
while ((match = reExportRegex.exec(source)) !== null) {
|
|
2282
|
+
const [statement, specifier] = match;
|
|
2283
|
+
addImport({
|
|
2284
|
+
statement,
|
|
2285
|
+
specifier,
|
|
2286
|
+
type: "named",
|
|
2287
|
+
line: getLineNumber(source, match.index),
|
|
2288
|
+
column: getColumnNumber(source, match.index)
|
|
2289
|
+
});
|
|
2290
|
+
}
|
|
2291
|
+
const reExportAllRegex = new RegExp(IMPORT_PATTERNS.reExportAll.source, "g");
|
|
2292
|
+
while ((match = reExportAllRegex.exec(source)) !== null) {
|
|
2293
|
+
const [statement, specifier] = match;
|
|
2294
|
+
addImport({
|
|
2295
|
+
statement,
|
|
2296
|
+
specifier,
|
|
2297
|
+
type: "namespace",
|
|
2298
|
+
line: getLineNumber(source, match.index),
|
|
2299
|
+
column: getColumnNumber(source, match.index)
|
|
2300
|
+
});
|
|
2301
|
+
}
|
|
2302
|
+
const externalImports = imports.filter((imp) => isExternalImport(imp.specifier));
|
|
2303
|
+
const relativeImports = imports.filter((imp) => isRelativeImport(imp.specifier));
|
|
2304
|
+
const externalPackages = [...new Set(externalImports.map((imp) => getPackageName(imp.specifier)))];
|
|
2305
|
+
return {
|
|
2306
|
+
imports,
|
|
2307
|
+
externalImports,
|
|
2308
|
+
relativeImports,
|
|
2309
|
+
externalPackages
|
|
2310
|
+
};
|
|
2311
|
+
}
|
|
2312
|
+
|
|
2313
|
+
// libs/uipack/src/utils/escape-html.ts
|
|
2314
|
+
function escapeHtmlAttr(str) {
|
|
2315
|
+
return str.replace(/&/g, "&").replace(/"/g, """);
|
|
2316
|
+
}
|
|
2317
|
+
|
|
2318
|
+
// libs/uipack/src/dependency/import-map.ts
|
|
2319
|
+
function createImportMap(dependencies) {
|
|
2320
|
+
const imports = {};
|
|
2321
|
+
const integrity = {};
|
|
2322
|
+
for (const dep of dependencies) {
|
|
2323
|
+
imports[dep.packageName] = dep.cdnUrl;
|
|
2324
|
+
if (dep.integrity) {
|
|
2325
|
+
integrity[dep.cdnUrl] = dep.integrity;
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2328
|
+
return {
|
|
2329
|
+
imports,
|
|
2330
|
+
integrity: Object.keys(integrity).length > 0 ? integrity : void 0
|
|
2331
|
+
};
|
|
2332
|
+
}
|
|
2333
|
+
function generateImportMapScriptTag(map) {
|
|
2334
|
+
const json = JSON.stringify(map, null, 2).replace(/<\//g, "<\\/");
|
|
2335
|
+
return `<script type="importmap">
|
|
2336
|
+
${json}
|
|
2337
|
+
</script>`;
|
|
2338
|
+
}
|
|
2339
|
+
function generateImportMapScriptTagMinified(map) {
|
|
2340
|
+
const json = JSON.stringify(map).replace(/<\//g, "<\\/");
|
|
2341
|
+
return `<script type="importmap">${json}</script>`;
|
|
2342
|
+
}
|
|
2343
|
+
function generateUMDShim(dependencies, options = {}) {
|
|
2344
|
+
const { safe = true, minify = false } = options;
|
|
2345
|
+
const depsWithGlobals = dependencies.filter((d) => d.global && !d.esm);
|
|
2346
|
+
if (depsWithGlobals.length === 0) {
|
|
2347
|
+
return "";
|
|
2348
|
+
}
|
|
2349
|
+
const entries = depsWithGlobals.map((dep) => {
|
|
2350
|
+
const global = dep.global;
|
|
2351
|
+
return `'${dep.packageName}': { default: window.${global}, ...window.${global} }`;
|
|
2352
|
+
});
|
|
2353
|
+
const shimObject = `{
|
|
2354
|
+
${entries.join(",\n ")}
|
|
2355
|
+
}`;
|
|
2356
|
+
const code = safe ? `(function() {
|
|
2357
|
+
try {
|
|
2358
|
+
window.__esm_shim = ${shimObject};
|
|
2359
|
+
} catch (e) {
|
|
2360
|
+
console.warn('UMD shim failed:', e);
|
|
2361
|
+
}
|
|
2362
|
+
})();` : `window.__esm_shim = ${shimObject};`;
|
|
2363
|
+
return minify ? code.replace(/\s+/g, " ").replace(/\s*([{},:])\s*/g, "$1") : code;
|
|
2364
|
+
}
|
|
2365
|
+
function generateCDNScriptTags(dependencies) {
|
|
2366
|
+
return dependencies.filter((dep) => !dep.esm).map((dep) => {
|
|
2367
|
+
const attrs = [`src="${escapeHtmlAttr(dep.cdnUrl)}"`];
|
|
2368
|
+
if (dep.integrity) {
|
|
2369
|
+
attrs.push(`integrity="${escapeHtmlAttr(dep.integrity)}"`);
|
|
2370
|
+
}
|
|
2371
|
+
attrs.push('crossorigin="anonymous"');
|
|
2372
|
+
return `<script ${attrs.join(" ")}></script>`;
|
|
2373
|
+
});
|
|
2374
|
+
}
|
|
2375
|
+
function generateESMScriptTags(dependencies) {
|
|
2376
|
+
return dependencies.filter((dep) => dep.esm).map((dep) => {
|
|
2377
|
+
const attrs = ['type="module"', `src="${escapeHtmlAttr(dep.cdnUrl)}"`];
|
|
2378
|
+
if (dep.integrity) {
|
|
2379
|
+
attrs.push(`integrity="${escapeHtmlAttr(dep.integrity)}"`);
|
|
2380
|
+
}
|
|
2381
|
+
attrs.push('crossorigin="anonymous"');
|
|
2382
|
+
return `<script ${attrs.join(" ")}></script>`;
|
|
2383
|
+
});
|
|
2384
|
+
}
|
|
2385
|
+
function generateDependencyHTML(dependencies, options = {}) {
|
|
2386
|
+
const { minify = false, includeShim = true } = options;
|
|
2387
|
+
const parts = [];
|
|
2388
|
+
const importMap = createImportMap(dependencies);
|
|
2389
|
+
const importMapTag = minify ? generateImportMapScriptTagMinified(importMap) : generateImportMapScriptTag(importMap);
|
|
2390
|
+
parts.push(importMapTag);
|
|
2391
|
+
const umdTags = generateCDNScriptTags(dependencies);
|
|
2392
|
+
parts.push(...umdTags);
|
|
2393
|
+
if (includeShim) {
|
|
2394
|
+
const shim = generateUMDShim(dependencies, { minify });
|
|
2395
|
+
if (shim) {
|
|
2396
|
+
parts.push(`<script>${shim}</script>`);
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
const esmTags = generateESMScriptTags(dependencies);
|
|
2400
|
+
parts.push(...esmTags);
|
|
2401
|
+
return parts.join(minify ? "" : "\n");
|
|
2402
|
+
}
|
|
2403
|
+
|
|
2404
|
+
// libs/uipack/src/dependency/resolver.ts
|
|
2405
|
+
var DependencyResolutionError = class extends Error {
|
|
2406
|
+
constructor(packageName, reason) {
|
|
2407
|
+
super(`Failed to resolve dependency "${packageName}": ${reason}`);
|
|
2408
|
+
this.packageName = packageName;
|
|
2409
|
+
this.reason = reason;
|
|
2410
|
+
this.name = "DependencyResolutionError";
|
|
2411
|
+
}
|
|
2412
|
+
};
|
|
2413
|
+
var NoProviderError = class extends DependencyResolutionError {
|
|
2414
|
+
constructor(packageName, platform) {
|
|
2415
|
+
super(packageName, `No CDN provider available for platform "${platform}"`);
|
|
2416
|
+
this.platform = platform;
|
|
2417
|
+
this.name = "NoProviderError";
|
|
2418
|
+
}
|
|
2419
|
+
};
|
|
2420
|
+
var DependencyResolver = class {
|
|
2421
|
+
options;
|
|
2422
|
+
registry;
|
|
2423
|
+
constructor(options = {}) {
|
|
2424
|
+
this.options = {
|
|
2425
|
+
platform: options.platform ?? "unknown",
|
|
2426
|
+
preferredProviders: options.preferredProviders ?? CDN_PROVIDER_PRIORITY[options.platform ?? "unknown"],
|
|
2427
|
+
customRegistry: options.customRegistry ?? {},
|
|
2428
|
+
strictMode: options.strictMode ?? true,
|
|
2429
|
+
requireIntegrity: options.requireIntegrity ?? false
|
|
2430
|
+
};
|
|
2431
|
+
this.registry = mergeRegistries(this.options.customRegistry);
|
|
2432
|
+
}
|
|
2433
|
+
/**
|
|
2434
|
+
* Resolve a single package to its CDN dependency.
|
|
2435
|
+
*
|
|
2436
|
+
* @param packageName - NPM package name
|
|
2437
|
+
* @param override - Optional explicit CDN dependency override
|
|
2438
|
+
* @returns Resolved dependency, or null in non-strict mode if package is not found (should be bundled)
|
|
2439
|
+
* @throws DependencyResolutionError if package cannot be resolved in strict mode
|
|
2440
|
+
*/
|
|
2441
|
+
resolve(packageName, override) {
|
|
2442
|
+
if (override) {
|
|
2443
|
+
return this.createResolvedDependency(packageName, override, "custom");
|
|
2444
|
+
}
|
|
2445
|
+
const entry = lookupPackage(packageName, this.registry);
|
|
2446
|
+
if (!entry) {
|
|
2447
|
+
if (this.options.strictMode) {
|
|
2448
|
+
throw new DependencyResolutionError(
|
|
2449
|
+
packageName,
|
|
2450
|
+
'Package not found in CDN registry. Add it to "dependencies" for explicit CDN configuration.'
|
|
2451
|
+
);
|
|
2452
|
+
}
|
|
2453
|
+
return null;
|
|
2454
|
+
}
|
|
2455
|
+
const providerPriority = this.options.preferredProviders;
|
|
2456
|
+
for (const provider of providerPriority) {
|
|
2457
|
+
const config = entry.providers[provider];
|
|
2458
|
+
if (config?.url) {
|
|
2459
|
+
if (this.options.requireIntegrity && !config.integrity) {
|
|
2460
|
+
continue;
|
|
2461
|
+
}
|
|
2462
|
+
return this.createResolvedDependency(packageName, config, provider, entry.defaultVersion);
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
throw new NoProviderError(packageName, this.options.platform);
|
|
2466
|
+
}
|
|
2467
|
+
/**
|
|
2468
|
+
* Resolve multiple packages.
|
|
2469
|
+
*
|
|
2470
|
+
* @param packageNames - Array of package names
|
|
2471
|
+
* @param overrides - Optional explicit overrides for specific packages
|
|
2472
|
+
* @returns Array of resolved dependencies (in dependency order)
|
|
2473
|
+
*/
|
|
2474
|
+
resolveMany(packageNames, overrides) {
|
|
2475
|
+
const allPackages = resolveAllDependencies(packageNames, this.options.platform, this.registry);
|
|
2476
|
+
const resolved = [];
|
|
2477
|
+
for (const pkgName of allPackages) {
|
|
2478
|
+
try {
|
|
2479
|
+
const override = overrides?.[pkgName];
|
|
2480
|
+
const dep = this.resolve(pkgName, override);
|
|
2481
|
+
if (dep) {
|
|
2482
|
+
resolved.push(dep);
|
|
2483
|
+
}
|
|
2484
|
+
} catch (error) {
|
|
2485
|
+
if (this.options.strictMode) {
|
|
2486
|
+
throw error;
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
return resolved;
|
|
2491
|
+
}
|
|
2492
|
+
/**
|
|
2493
|
+
* Resolve dependencies from source code.
|
|
2494
|
+
*
|
|
2495
|
+
* Parses the source to extract imports, then resolves external packages
|
|
2496
|
+
* that are in the externals list.
|
|
2497
|
+
*
|
|
2498
|
+
* @param source - Source code to parse
|
|
2499
|
+
* @param externals - Package names to resolve from CDN (others are bundled)
|
|
2500
|
+
* @param overrides - Optional explicit CDN overrides
|
|
2501
|
+
* @returns Resolved dependencies
|
|
2502
|
+
*/
|
|
2503
|
+
resolveFromSource(source, externals, overrides) {
|
|
2504
|
+
const parseResult = parseImports(source);
|
|
2505
|
+
const packagesToResolve = parseResult.externalPackages.filter((pkg) => externals.includes(pkg));
|
|
2506
|
+
return this.resolveMany(packagesToResolve, overrides);
|
|
2507
|
+
}
|
|
2508
|
+
/**
|
|
2509
|
+
* Generate an import map for resolved dependencies.
|
|
2510
|
+
*
|
|
2511
|
+
* @param dependencies - Resolved dependencies
|
|
2512
|
+
* @returns Browser import map
|
|
2513
|
+
*/
|
|
2514
|
+
generateImportMap(dependencies) {
|
|
2515
|
+
return createImportMap(dependencies);
|
|
2516
|
+
}
|
|
2517
|
+
/**
|
|
2518
|
+
* Check if a package can be resolved for the current platform.
|
|
2519
|
+
*
|
|
2520
|
+
* @param packageName - Package name to check
|
|
2521
|
+
* @returns true if the package can be resolved
|
|
2522
|
+
*/
|
|
2523
|
+
canResolve(packageName) {
|
|
2524
|
+
try {
|
|
2525
|
+
const result = this.resolve(packageName);
|
|
2526
|
+
return result !== null;
|
|
2527
|
+
} catch {
|
|
2528
|
+
return false;
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
/**
|
|
2532
|
+
* Get the resolved CDN URL for a package.
|
|
2533
|
+
*
|
|
2534
|
+
* @param packageName - Package name
|
|
2535
|
+
* @param override - Optional explicit override
|
|
2536
|
+
* @returns CDN URL or undefined if cannot resolve
|
|
2537
|
+
*/
|
|
2538
|
+
getUrl(packageName, override) {
|
|
2539
|
+
try {
|
|
2540
|
+
const resolved = this.resolve(packageName, override);
|
|
2541
|
+
return resolved?.cdnUrl;
|
|
2542
|
+
} catch {
|
|
2543
|
+
return void 0;
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
/**
|
|
2547
|
+
* Get peer dependencies for a package.
|
|
2548
|
+
*/
|
|
2549
|
+
getPeerDependencies(packageName) {
|
|
2550
|
+
return getPackagePeerDependencies(packageName, this.registry);
|
|
2551
|
+
}
|
|
2552
|
+
/**
|
|
2553
|
+
* Create the current registry (default + custom).
|
|
2554
|
+
*/
|
|
2555
|
+
getRegistry() {
|
|
2556
|
+
return this.registry;
|
|
2557
|
+
}
|
|
2558
|
+
/**
|
|
2559
|
+
* Get the current platform.
|
|
2560
|
+
*/
|
|
2561
|
+
getPlatform() {
|
|
2562
|
+
return this.options.platform;
|
|
2563
|
+
}
|
|
2564
|
+
/**
|
|
2565
|
+
* Create a resolved dependency object.
|
|
2566
|
+
*/
|
|
2567
|
+
createResolvedDependency(packageName, config, provider, version) {
|
|
2568
|
+
return {
|
|
2569
|
+
packageName,
|
|
2570
|
+
version: version ?? this.extractVersionFromUrl(config.url) ?? "latest",
|
|
2571
|
+
cdnUrl: config.url,
|
|
2572
|
+
integrity: config.integrity,
|
|
2573
|
+
global: config.global,
|
|
2574
|
+
esm: config.esm ?? false,
|
|
2575
|
+
provider
|
|
2576
|
+
};
|
|
2577
|
+
}
|
|
2578
|
+
/**
|
|
2579
|
+
* Try to extract version from CDN URL.
|
|
2580
|
+
*/
|
|
2581
|
+
extractVersionFromUrl(url) {
|
|
2582
|
+
const versionMatch = url.match(/@(\d+\.\d+\.\d+(?:-[\w.]+)?)/);
|
|
2583
|
+
if (versionMatch) {
|
|
2584
|
+
return versionMatch[1];
|
|
2585
|
+
}
|
|
2586
|
+
const versionMatch2 = url.match(/\/v?(\d+\.\d+\.\d+)\//);
|
|
2587
|
+
if (versionMatch2) {
|
|
2588
|
+
return versionMatch2[1];
|
|
2589
|
+
}
|
|
2590
|
+
return void 0;
|
|
2591
|
+
}
|
|
2592
|
+
};
|
|
2593
|
+
|
|
2594
|
+
// libs/uipack/src/bundler/file-cache/component-builder.ts
|
|
2595
|
+
var ComponentBuilder = class {
|
|
2596
|
+
storage;
|
|
2597
|
+
esbuild = null;
|
|
2598
|
+
constructor(storage) {
|
|
2599
|
+
this.storage = storage;
|
|
2600
|
+
}
|
|
2601
|
+
/**
|
|
2602
|
+
* Build a component from a file path.
|
|
2603
|
+
*/
|
|
2604
|
+
async build(options) {
|
|
2605
|
+
const startTime = performance.now();
|
|
2606
|
+
const {
|
|
2607
|
+
entryPath,
|
|
2608
|
+
toolName,
|
|
2609
|
+
externals = [],
|
|
2610
|
+
dependencies = {},
|
|
2611
|
+
bundleOptions = {},
|
|
2612
|
+
platform = "unknown",
|
|
2613
|
+
skipCache = false,
|
|
2614
|
+
ssr = false,
|
|
2615
|
+
ssrContext = {},
|
|
2616
|
+
executeCode: executeCode2
|
|
2617
|
+
} = options;
|
|
2618
|
+
const absoluteEntryPath = resolve2(entryPath);
|
|
2619
|
+
if (!existsSync3(absoluteEntryPath)) {
|
|
2620
|
+
throw new Error(`Entry file not found: ${absoluteEntryPath}`);
|
|
2621
|
+
}
|
|
2622
|
+
const hashResult = await calculateComponentHash({
|
|
2623
|
+
entryPath: absoluteEntryPath,
|
|
2624
|
+
externals,
|
|
2625
|
+
dependencies,
|
|
2626
|
+
bundleOptions
|
|
2627
|
+
});
|
|
2628
|
+
if (!skipCache) {
|
|
2629
|
+
const cached = await this.storage.get(hashResult.hash);
|
|
2630
|
+
if (cached) {
|
|
2631
|
+
return {
|
|
2632
|
+
manifest: cached,
|
|
2633
|
+
cached: true,
|
|
2634
|
+
buildTimeMs: performance.now() - startTime
|
|
2635
|
+
};
|
|
2636
|
+
}
|
|
2637
|
+
}
|
|
2638
|
+
const source = await readFile3(absoluteEntryPath, "utf8");
|
|
2639
|
+
const resolver = new DependencyResolver({ platform });
|
|
2640
|
+
const resolvedDeps = [];
|
|
2641
|
+
for (const pkg of externals) {
|
|
2642
|
+
try {
|
|
2643
|
+
const override = dependencies[pkg];
|
|
2644
|
+
const resolved = resolver.resolve(pkg, override);
|
|
2645
|
+
if (resolved) {
|
|
2646
|
+
resolvedDeps.push(resolved);
|
|
2647
|
+
}
|
|
2648
|
+
} catch (error) {
|
|
2649
|
+
console.warn(`Failed to resolve external "${pkg}": ${error}`);
|
|
2650
|
+
}
|
|
2651
|
+
}
|
|
2652
|
+
const allExternals = new Set(externals);
|
|
2653
|
+
for (const dep of resolvedDeps) {
|
|
2654
|
+
const entry = resolver.getRegistry()[dep.packageName];
|
|
2655
|
+
if (entry?.providers) {
|
|
2656
|
+
const providerConfig = Object.values(entry.providers)[0];
|
|
2657
|
+
if (providerConfig?.peerDependencies) {
|
|
2658
|
+
for (const peer of providerConfig.peerDependencies) {
|
|
2659
|
+
if (!allExternals.has(peer)) {
|
|
2660
|
+
allExternals.add(peer);
|
|
2661
|
+
try {
|
|
2662
|
+
const peerOverride = dependencies[peer];
|
|
2663
|
+
const resolved = resolver.resolve(peer, peerOverride);
|
|
2664
|
+
if (resolved) {
|
|
2665
|
+
resolvedDeps.push(resolved);
|
|
2666
|
+
}
|
|
2667
|
+
} catch {
|
|
2668
|
+
}
|
|
2669
|
+
}
|
|
2670
|
+
}
|
|
2671
|
+
}
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2674
|
+
const importMap = createImportMap(resolvedDeps);
|
|
2675
|
+
const bundleResult = await this.bundleComponent({
|
|
2676
|
+
source,
|
|
2677
|
+
entryPath: absoluteEntryPath,
|
|
2678
|
+
externals: Array.from(allExternals),
|
|
2679
|
+
bundleOptions
|
|
2680
|
+
});
|
|
2681
|
+
let ssrHtml;
|
|
2682
|
+
if (ssr) {
|
|
2683
|
+
ssrHtml = await this.renderSSR(bundleResult.code, ssrContext, resolvedDeps, executeCode2);
|
|
2684
|
+
}
|
|
2685
|
+
const manifest = {
|
|
2686
|
+
version: "1.0",
|
|
2687
|
+
buildId: randomUUID(),
|
|
2688
|
+
toolName,
|
|
2689
|
+
entryPath: absoluteEntryPath,
|
|
2690
|
+
contentHash: hashResult.hash,
|
|
2691
|
+
dependencies: resolvedDeps,
|
|
2692
|
+
outputs: {
|
|
2693
|
+
code: bundleResult.code,
|
|
2694
|
+
sourceMap: bundleResult.map,
|
|
2695
|
+
ssrHtml
|
|
2696
|
+
},
|
|
2697
|
+
importMap,
|
|
2698
|
+
metadata: {
|
|
2699
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2700
|
+
buildTimeMs: performance.now() - startTime,
|
|
2701
|
+
totalSize: Buffer.byteLength(bundleResult.code, "utf8"),
|
|
2702
|
+
bundlerVersion: bundleResult.bundlerVersion
|
|
2703
|
+
}
|
|
2704
|
+
};
|
|
2705
|
+
await this.storage.set(hashResult.hash, manifest);
|
|
2706
|
+
return {
|
|
2707
|
+
manifest,
|
|
2708
|
+
cached: false,
|
|
2709
|
+
buildTimeMs: performance.now() - startTime
|
|
2710
|
+
};
|
|
2711
|
+
}
|
|
2712
|
+
/**
|
|
2713
|
+
* Build multiple components.
|
|
2714
|
+
*/
|
|
2715
|
+
async buildMany(options) {
|
|
2716
|
+
return Promise.all(options.map((opt) => this.build(opt)));
|
|
2717
|
+
}
|
|
2718
|
+
/**
|
|
2719
|
+
* Check if a component needs rebuilding.
|
|
2720
|
+
*/
|
|
2721
|
+
async needsRebuild(options) {
|
|
2722
|
+
const absoluteEntryPath = resolve2(options.entryPath);
|
|
2723
|
+
const hashResult = await calculateComponentHash({
|
|
2724
|
+
entryPath: absoluteEntryPath,
|
|
2725
|
+
externals: options.externals,
|
|
2726
|
+
dependencies: options.dependencies,
|
|
2727
|
+
bundleOptions: options.bundleOptions
|
|
2728
|
+
});
|
|
2729
|
+
const cached = await this.storage.has(hashResult.hash);
|
|
2730
|
+
return !cached;
|
|
2731
|
+
}
|
|
2732
|
+
/**
|
|
2733
|
+
* Get a cached build if it exists.
|
|
2734
|
+
*/
|
|
2735
|
+
async getCached(options) {
|
|
2736
|
+
const absoluteEntryPath = resolve2(options.entryPath);
|
|
2737
|
+
const hashResult = await calculateComponentHash({
|
|
2738
|
+
entryPath: absoluteEntryPath,
|
|
2739
|
+
externals: options.externals,
|
|
2740
|
+
dependencies: options.dependencies,
|
|
2741
|
+
bundleOptions: options.bundleOptions
|
|
2742
|
+
});
|
|
2743
|
+
return this.storage.get(hashResult.hash);
|
|
2744
|
+
}
|
|
2745
|
+
/**
|
|
2746
|
+
* Invalidate a cached build.
|
|
2747
|
+
*/
|
|
2748
|
+
async invalidate(contentHash) {
|
|
2749
|
+
return this.storage.delete(contentHash);
|
|
2750
|
+
}
|
|
2751
|
+
/**
|
|
2752
|
+
* Generate complete HTML for a built component.
|
|
2753
|
+
*/
|
|
2754
|
+
generateHTML(manifest, minify = false) {
|
|
2755
|
+
const parts = [];
|
|
2756
|
+
const dependencyHtml = generateDependencyHTML(manifest.dependencies, { minify });
|
|
2757
|
+
parts.push(dependencyHtml);
|
|
2758
|
+
parts.push(`<script type="module">${manifest.outputs.code}</script>`);
|
|
2759
|
+
return parts.join(minify ? "" : "\n");
|
|
2760
|
+
}
|
|
2761
|
+
/**
|
|
2762
|
+
* Bundle a component using esbuild.
|
|
2763
|
+
*/
|
|
2764
|
+
async bundleComponent(options) {
|
|
2765
|
+
const { source, entryPath, externals, bundleOptions } = options;
|
|
2766
|
+
if (!this.esbuild) {
|
|
2767
|
+
try {
|
|
2768
|
+
this.esbuild = await import("esbuild");
|
|
2769
|
+
} catch {
|
|
2770
|
+
throw new Error("esbuild is required for component building. Install with: npm install esbuild");
|
|
2771
|
+
}
|
|
2772
|
+
}
|
|
2773
|
+
const ext = extname(entryPath).toLowerCase();
|
|
2774
|
+
const loader = ext === ".tsx" ? "tsx" : ext === ".ts" ? "ts" : ext === ".jsx" ? "jsx" : "js";
|
|
2775
|
+
try {
|
|
2776
|
+
const result = await this.esbuild.transform(source, {
|
|
2777
|
+
loader,
|
|
2778
|
+
format: "esm",
|
|
2779
|
+
minify: bundleOptions.minify ?? process.env["NODE_ENV"] === "production",
|
|
2780
|
+
sourcemap: bundleOptions.sourceMaps ? "inline" : false,
|
|
2781
|
+
target: bundleOptions.target ?? "es2020",
|
|
2782
|
+
treeShaking: bundleOptions.treeShake ?? true,
|
|
2783
|
+
jsx: "automatic",
|
|
2784
|
+
jsxImportSource: bundleOptions.jsxImportSource ?? "react",
|
|
2785
|
+
// Mark externals for later import map resolution
|
|
2786
|
+
banner: externals.length > 0 ? `/* externals: ${externals.join(", ")} */` : void 0
|
|
2787
|
+
});
|
|
2788
|
+
return {
|
|
2789
|
+
code: result.code,
|
|
2790
|
+
map: result.map || void 0,
|
|
2791
|
+
bundlerVersion: this.esbuild.version
|
|
2792
|
+
};
|
|
2793
|
+
} catch (error) {
|
|
2794
|
+
throw new Error(`Bundle failed for ${entryPath}: ${error}`);
|
|
2795
|
+
}
|
|
2796
|
+
}
|
|
2797
|
+
/**
|
|
2798
|
+
* Perform server-side rendering.
|
|
2799
|
+
*/
|
|
2800
|
+
async renderSSR(code, context, dependencies, executeCode2) {
|
|
2801
|
+
const hasReact = dependencies.some((d) => d.packageName === "react");
|
|
2802
|
+
if (!hasReact) {
|
|
2803
|
+
console.warn("SSR requires React as an external dependency");
|
|
2804
|
+
return void 0;
|
|
2805
|
+
}
|
|
2806
|
+
try {
|
|
2807
|
+
const React = await import("react");
|
|
2808
|
+
const ReactDOMServer = await import("react-dom/server");
|
|
2809
|
+
const exports = {};
|
|
2810
|
+
const module = { exports };
|
|
2811
|
+
if (executeCode2) {
|
|
2812
|
+
executeCode2(code, exports, module, React);
|
|
2813
|
+
} else {
|
|
2814
|
+
const fn = new Function("exports", "module", "React", code);
|
|
2815
|
+
fn(exports, module, React);
|
|
2816
|
+
}
|
|
2817
|
+
const Component = module.exports.default || module.exports;
|
|
2818
|
+
if (typeof Component !== "function") {
|
|
2819
|
+
console.warn("SSR: No default component export found");
|
|
2820
|
+
return void 0;
|
|
2821
|
+
}
|
|
2822
|
+
const element = React.createElement(Component, context);
|
|
2823
|
+
return ReactDOMServer.renderToString(element);
|
|
2824
|
+
} catch (error) {
|
|
2825
|
+
console.warn(`SSR failed: ${error}`);
|
|
2826
|
+
return void 0;
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
};
|
|
2830
|
+
async function createFilesystemBuilder(cacheDir = ".frontmcp-cache/builds") {
|
|
2831
|
+
const { FilesystemStorage: FilesystemStorage2 } = await Promise.resolve().then(() => (init_filesystem(), filesystem_exports));
|
|
2832
|
+
const storage = new FilesystemStorage2({ cacheDir });
|
|
2833
|
+
await storage.initialize();
|
|
2834
|
+
return new ComponentBuilder(storage);
|
|
2835
|
+
}
|
|
2836
|
+
async function createRedisBuilder(redisClient, keyPrefix = "frontmcp:ui:build:") {
|
|
2837
|
+
const { RedisStorage: RedisStorage2 } = await Promise.resolve().then(() => (init_redis(), redis_exports));
|
|
2838
|
+
const storage = new RedisStorage2({
|
|
2839
|
+
client: redisClient,
|
|
2840
|
+
keyPrefix
|
|
2841
|
+
});
|
|
2842
|
+
await storage.initialize();
|
|
2843
|
+
return new ComponentBuilder(storage);
|
|
2844
|
+
}
|
|
2845
|
+
export {
|
|
2846
|
+
BundlerCache,
|
|
2847
|
+
ComponentBuilder,
|
|
2848
|
+
DEFAULT_BUNDLER_OPTIONS,
|
|
2849
|
+
DEFAULT_BUNDLE_OPTIONS,
|
|
2850
|
+
DEFAULT_SECURITY_POLICY,
|
|
2851
|
+
DEFAULT_STATIC_HTML_OPTIONS,
|
|
2852
|
+
DEFAULT_STORAGE_OPTIONS,
|
|
2853
|
+
ExecutionError,
|
|
2854
|
+
FilesystemStorage,
|
|
2855
|
+
RedisStorage,
|
|
2856
|
+
STATIC_HTML_CDN,
|
|
2857
|
+
SecurityError,
|
|
2858
|
+
buildIdFromHash,
|
|
2859
|
+
calculateComponentHash,
|
|
2860
|
+
calculateManifestSize,
|
|
2861
|
+
calculateQuickHash,
|
|
2862
|
+
createCacheKey,
|
|
2863
|
+
createFilesystemBuilder,
|
|
2864
|
+
createFilesystemStorage,
|
|
2865
|
+
createRedisBuilder,
|
|
2866
|
+
createRedisStorage,
|
|
2867
|
+
executeCode,
|
|
2868
|
+
executeDefault,
|
|
2869
|
+
generateBuildId,
|
|
2870
|
+
getCdnTypeForPlatform,
|
|
2871
|
+
hashContent,
|
|
2872
|
+
hashFile,
|
|
2873
|
+
hashFiles,
|
|
2874
|
+
isExecutionError,
|
|
2875
|
+
mergePolicy,
|
|
2876
|
+
sha256,
|
|
2877
|
+
sha256Buffer,
|
|
2878
|
+
throwOnViolations,
|
|
2879
|
+
validateImports,
|
|
2880
|
+
validateSize,
|
|
2881
|
+
validateSource
|
|
2882
|
+
};
|