enpilink 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +289 -0
- package/bin/run.js +5 -0
- package/dist/cli/build-helpers.d.ts +8 -0
- package/dist/cli/build-helpers.js +105 -0
- package/dist/cli/build-helpers.js.map +1 -0
- package/dist/cli/build-helpers.test.d.ts +1 -0
- package/dist/cli/build-helpers.test.js +100 -0
- package/dist/cli/build-helpers.test.js.map +1 -0
- package/dist/cli/detect-port.d.ts +18 -0
- package/dist/cli/detect-port.js +50 -0
- package/dist/cli/detect-port.js.map +1 -0
- package/dist/cli/ensure-ssh-key.d.ts +17 -0
- package/dist/cli/ensure-ssh-key.js +45 -0
- package/dist/cli/ensure-ssh-key.js.map +1 -0
- package/dist/cli/ensure-ssh-key.test.d.ts +1 -0
- package/dist/cli/ensure-ssh-key.test.js +68 -0
- package/dist/cli/ensure-ssh-key.test.js.map +1 -0
- package/dist/cli/header.d.ts +4 -0
- package/dist/cli/header.js +6 -0
- package/dist/cli/header.js.map +1 -0
- package/dist/cli/resolve-views-dir.d.ts +1 -0
- package/dist/cli/resolve-views-dir.js +17 -0
- package/dist/cli/resolve-views-dir.js.map +1 -0
- package/dist/cli/run-command.d.ts +2 -0
- package/dist/cli/run-command.js +43 -0
- package/dist/cli/run-command.js.map +1 -0
- package/dist/cli/telemetry.d.ts +14 -0
- package/dist/cli/telemetry.js +24 -0
- package/dist/cli/telemetry.js.map +1 -0
- package/dist/cli/tunnel-control-server.d.ts +11 -0
- package/dist/cli/tunnel-control-server.js +35 -0
- package/dist/cli/tunnel-control-server.js.map +1 -0
- package/dist/cli/tunnel-control-server.test.d.ts +1 -0
- package/dist/cli/tunnel-control-server.test.js +39 -0
- package/dist/cli/tunnel-control-server.test.js.map +1 -0
- package/dist/cli/tunnel-handler.d.ts +3 -0
- package/dist/cli/tunnel-handler.js +48 -0
- package/dist/cli/tunnel-handler.js.map +1 -0
- package/dist/cli/tunnel-handler.test.d.ts +1 -0
- package/dist/cli/tunnel-handler.test.js +107 -0
- package/dist/cli/tunnel-handler.test.js.map +1 -0
- package/dist/cli/tunnel-providers/index.d.ts +5 -0
- package/dist/cli/tunnel-providers/index.js +5 -0
- package/dist/cli/tunnel-providers/index.js.map +1 -0
- package/dist/cli/tunnel-providers/srv-us.d.ts +18 -0
- package/dist/cli/tunnel-providers/srv-us.js +66 -0
- package/dist/cli/tunnel-providers/srv-us.js.map +1 -0
- package/dist/cli/tunnel-providers/srv-us.test.d.ts +1 -0
- package/dist/cli/tunnel-providers/srv-us.test.js +74 -0
- package/dist/cli/tunnel-providers/srv-us.test.js.map +1 -0
- package/dist/cli/tunnel-providers/types.d.ts +49 -0
- package/dist/cli/tunnel-providers/types.js +2 -0
- package/dist/cli/tunnel-providers/types.js.map +1 -0
- package/dist/cli/tunnel.d.ts +75 -0
- package/dist/cli/tunnel.js +254 -0
- package/dist/cli/tunnel.js.map +1 -0
- package/dist/cli/tunnel.test.d.ts +1 -0
- package/dist/cli/tunnel.test.js +255 -0
- package/dist/cli/tunnel.test.js.map +1 -0
- package/dist/cli/types.d.ts +5 -0
- package/dist/cli/types.js +2 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli/use-execute-steps.d.ts +11 -0
- package/dist/cli/use-execute-steps.js +36 -0
- package/dist/cli/use-execute-steps.js.map +1 -0
- package/dist/cli/use-messages.d.ts +3 -0
- package/dist/cli/use-messages.js +11 -0
- package/dist/cli/use-messages.js.map +1 -0
- package/dist/cli/use-nodemon.d.ts +2 -0
- package/dist/cli/use-nodemon.js +73 -0
- package/dist/cli/use-nodemon.js.map +1 -0
- package/dist/cli/use-open-browser.d.ts +1 -0
- package/dist/cli/use-open-browser.js +44 -0
- package/dist/cli/use-open-browser.js.map +1 -0
- package/dist/cli/use-open-tunnel-browser.d.ts +6 -0
- package/dist/cli/use-open-tunnel-browser.js +19 -0
- package/dist/cli/use-open-tunnel-browser.js.map +1 -0
- package/dist/cli/use-tunnel.d.ts +17 -0
- package/dist/cli/use-tunnel.js +131 -0
- package/dist/cli/use-tunnel.js.map +1 -0
- package/dist/cli/use-typescript-check.d.ts +9 -0
- package/dist/cli/use-typescript-check.js +94 -0
- package/dist/cli/use-typescript-check.js.map +1 -0
- package/dist/commands/build.d.ts +8 -0
- package/dist/commands/build.js +97 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/create.d.ts +9 -0
- package/dist/commands/create.js +30 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/dev.d.ts +13 -0
- package/dist/commands/dev.js +112 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/start.d.ts +10 -0
- package/dist/commands/start.js +76 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/telemetry/disable.d.ts +5 -0
- package/dist/commands/telemetry/disable.js +12 -0
- package/dist/commands/telemetry/disable.js.map +1 -0
- package/dist/commands/telemetry/enable.d.ts +5 -0
- package/dist/commands/telemetry/enable.js +12 -0
- package/dist/commands/telemetry/enable.js.map +1 -0
- package/dist/commands/telemetry/status.d.ts +5 -0
- package/dist/commands/telemetry/status.js +12 -0
- package/dist/commands/telemetry/status.js.map +1 -0
- package/dist/server/admin.d.ts +79 -0
- package/dist/server/admin.js +239 -0
- package/dist/server/admin.js.map +1 -0
- package/dist/server/admin.test.d.ts +1 -0
- package/dist/server/admin.test.js +226 -0
- package/dist/server/admin.test.js.map +1 -0
- package/dist/server/analytics.d.ts +60 -0
- package/dist/server/analytics.js +168 -0
- package/dist/server/analytics.js.map +1 -0
- package/dist/server/analytics.test.d.ts +1 -0
- package/dist/server/analytics.test.js +179 -0
- package/dist/server/analytics.test.js.map +1 -0
- package/dist/server/asset-base-url-transform-plugin.d.ts +11 -0
- package/dist/server/asset-base-url-transform-plugin.js +48 -0
- package/dist/server/asset-base-url-transform-plugin.js.map +1 -0
- package/dist/server/asset-base-url-transform-plugin.test.d.ts +1 -0
- package/dist/server/asset-base-url-transform-plugin.test.js +134 -0
- package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -0
- package/dist/server/auth.d.ts +20 -0
- package/dist/server/auth.js +28 -0
- package/dist/server/auth.js.map +1 -0
- package/dist/server/build-manifest.test.d.ts +1 -0
- package/dist/server/build-manifest.test.js +27 -0
- package/dist/server/build-manifest.test.js.map +1 -0
- package/dist/server/config/config.test.d.ts +1 -0
- package/dist/server/config/config.test.js +214 -0
- package/dist/server/config/config.test.js.map +1 -0
- package/dist/server/config/index.d.ts +3 -0
- package/dist/server/config/index.js +4 -0
- package/dist/server/config/index.js.map +1 -0
- package/dist/server/config/resolve.d.ts +73 -0
- package/dist/server/config/resolve.js +167 -0
- package/dist/server/config/resolve.js.map +1 -0
- package/dist/server/config/router.d.ts +23 -0
- package/dist/server/config/router.js +119 -0
- package/dist/server/config/router.js.map +1 -0
- package/dist/server/config/schema.d.ts +78 -0
- package/dist/server/config/schema.js +158 -0
- package/dist/server/config/schema.js.map +1 -0
- package/dist/server/content-helpers.d.ts +67 -0
- package/dist/server/content-helpers.js +79 -0
- package/dist/server/content-helpers.js.map +1 -0
- package/dist/server/content-helpers.test.d.ts +1 -0
- package/dist/server/content-helpers.test.js +70 -0
- package/dist/server/content-helpers.test.js.map +1 -0
- package/dist/server/express.d.ts +11 -0
- package/dist/server/express.js +129 -0
- package/dist/server/express.js.map +1 -0
- package/dist/server/express.test.d.ts +1 -0
- package/dist/server/express.test.js +464 -0
- package/dist/server/express.test.js.map +1 -0
- package/dist/server/file-ref.d.ts +28 -0
- package/dist/server/file-ref.js +27 -0
- package/dist/server/file-ref.js.map +1 -0
- package/dist/server/index.d.ts +17 -0
- package/dist/server/index.js +14 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/inferUtilityTypes.d.ts +64 -0
- package/dist/server/inferUtilityTypes.js +2 -0
- package/dist/server/inferUtilityTypes.js.map +1 -0
- package/dist/server/log-sink.d.ts +16 -0
- package/dist/server/log-sink.js +66 -0
- package/dist/server/log-sink.js.map +1 -0
- package/dist/server/metric.d.ts +12 -0
- package/dist/server/metric.js +13 -0
- package/dist/server/metric.js.map +1 -0
- package/dist/server/middleware.d.ts +137 -0
- package/dist/server/middleware.js +93 -0
- package/dist/server/middleware.js.map +1 -0
- package/dist/server/middleware.test-d.d.ts +1 -0
- package/dist/server/middleware.test-d.js +75 -0
- package/dist/server/middleware.test-d.js.map +1 -0
- package/dist/server/middleware.test.d.ts +1 -0
- package/dist/server/middleware.test.js +493 -0
- package/dist/server/middleware.test.js.map +1 -0
- package/dist/server/mock-seed.d.ts +62 -0
- package/dist/server/mock-seed.js +251 -0
- package/dist/server/mock-seed.js.map +1 -0
- package/dist/server/mock-seed.test.d.ts +1 -0
- package/dist/server/mock-seed.test.js +122 -0
- package/dist/server/mock-seed.test.js.map +1 -0
- package/dist/server/observability.d.ts +149 -0
- package/dist/server/observability.js +340 -0
- package/dist/server/observability.js.map +1 -0
- package/dist/server/observability.test.d.ts +1 -0
- package/dist/server/observability.test.js +251 -0
- package/dist/server/observability.test.js.map +1 -0
- package/dist/server/otel.d.ts +45 -0
- package/dist/server/otel.js +117 -0
- package/dist/server/otel.js.map +1 -0
- package/dist/server/otel.test.d.ts +1 -0
- package/dist/server/otel.test.js +122 -0
- package/dist/server/otel.test.js.map +1 -0
- package/dist/server/server.d.ts +422 -0
- package/dist/server/server.js +684 -0
- package/dist/server/server.js.map +1 -0
- package/dist/server/storage/index.d.ts +23 -0
- package/dist/server/storage/index.js +46 -0
- package/dist/server/storage/index.js.map +1 -0
- package/dist/server/storage/memory.d.ts +30 -0
- package/dist/server/storage/memory.js +98 -0
- package/dist/server/storage/memory.js.map +1 -0
- package/dist/server/storage/memory.test.d.ts +1 -0
- package/dist/server/storage/memory.test.js +81 -0
- package/dist/server/storage/memory.test.js.map +1 -0
- package/dist/server/storage/postgres.d.ts +65 -0
- package/dist/server/storage/postgres.js +242 -0
- package/dist/server/storage/postgres.js.map +1 -0
- package/dist/server/storage/postgres.test.d.ts +1 -0
- package/dist/server/storage/postgres.test.js +182 -0
- package/dist/server/storage/postgres.test.js.map +1 -0
- package/dist/server/storage/sqlite.d.ts +33 -0
- package/dist/server/storage/sqlite.js +250 -0
- package/dist/server/storage/sqlite.js.map +1 -0
- package/dist/server/storage/sqlite.test.d.ts +1 -0
- package/dist/server/storage/sqlite.test.js +133 -0
- package/dist/server/storage/sqlite.test.js.map +1 -0
- package/dist/server/storage/types.d.ts +119 -0
- package/dist/server/storage/types.js +11 -0
- package/dist/server/storage/types.js.map +1 -0
- package/dist/server/templateHelper.d.ts +16 -0
- package/dist/server/templateHelper.js +11 -0
- package/dist/server/templateHelper.js.map +1 -0
- package/dist/server/templates.generated.d.ts +4 -0
- package/dist/server/templates.generated.js +47 -0
- package/dist/server/templates.generated.js.map +1 -0
- package/dist/server/tunnel-proxy-router.d.ts +7 -0
- package/dist/server/tunnel-proxy-router.js +110 -0
- package/dist/server/tunnel-proxy-router.js.map +1 -0
- package/dist/server/tunnel-proxy-router.test.d.ts +1 -0
- package/dist/server/tunnel-proxy-router.test.js +229 -0
- package/dist/server/tunnel-proxy-router.test.js.map +1 -0
- package/dist/server/viewsDevServer.d.ts +14 -0
- package/dist/server/viewsDevServer.js +45 -0
- package/dist/server/viewsDevServer.js.map +1 -0
- package/dist/test/utils.d.ts +127 -0
- package/dist/test/utils.js +247 -0
- package/dist/test/utils.js.map +1 -0
- package/dist/test/view.test.d.ts +1 -0
- package/dist/test/view.test.js +568 -0
- package/dist/test/view.test.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/dist/web/bridges/apps-sdk/adaptor.d.ts +54 -0
- package/dist/web/bridges/apps-sdk/adaptor.js +164 -0
- package/dist/web/bridges/apps-sdk/adaptor.js.map +1 -0
- package/dist/web/bridges/apps-sdk/bridge.d.ts +11 -0
- package/dist/web/bridges/apps-sdk/bridge.js +47 -0
- package/dist/web/bridges/apps-sdk/bridge.js.map +1 -0
- package/dist/web/bridges/apps-sdk/index.d.ts +5 -0
- package/dist/web/bridges/apps-sdk/index.js +5 -0
- package/dist/web/bridges/apps-sdk/index.js.map +1 -0
- package/dist/web/bridges/apps-sdk/types.d.ts +147 -0
- package/dist/web/bridges/apps-sdk/types.js +10 -0
- package/dist/web/bridges/apps-sdk/types.js.map +1 -0
- package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +13 -0
- package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +18 -0
- package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -0
- package/dist/web/bridges/get-adaptor.d.ts +9 -0
- package/dist/web/bridges/get-adaptor.js +15 -0
- package/dist/web/bridges/get-adaptor.js.map +1 -0
- package/dist/web/bridges/index.d.ts +5 -0
- package/dist/web/bridges/index.js +6 -0
- package/dist/web/bridges/index.js.map +1 -0
- package/dist/web/bridges/mcp-app/adaptor.d.ts +81 -0
- package/dist/web/bridges/mcp-app/adaptor.js +346 -0
- package/dist/web/bridges/mcp-app/adaptor.js.map +1 -0
- package/dist/web/bridges/mcp-app/bridge.d.ts +28 -0
- package/dist/web/bridges/mcp-app/bridge.js +124 -0
- package/dist/web/bridges/mcp-app/bridge.js.map +1 -0
- package/dist/web/bridges/mcp-app/index.d.ts +4 -0
- package/dist/web/bridges/mcp-app/index.js +4 -0
- package/dist/web/bridges/mcp-app/index.js.map +1 -0
- package/dist/web/bridges/mcp-app/types.d.ts +8 -0
- package/dist/web/bridges/mcp-app/types.js +2 -0
- package/dist/web/bridges/mcp-app/types.js.map +1 -0
- package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +19 -0
- package/dist/web/bridges/mcp-app/use-mcp-app-context.js +19 -0
- package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -0
- package/dist/web/bridges/mcp-app/use-mcp-app-context.test.d.ts +1 -0
- package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +26 -0
- package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -0
- package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
- package/dist/web/bridges/mcp-app/view-tools.test.js +144 -0
- package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
- package/dist/web/bridges/types.d.ts +243 -0
- package/dist/web/bridges/types.js +2 -0
- package/dist/web/bridges/types.js.map +1 -0
- package/dist/web/bridges/use-host-context.d.ts +7 -0
- package/dist/web/bridges/use-host-context.js +13 -0
- package/dist/web/bridges/use-host-context.js.map +1 -0
- package/dist/web/components/modal-provider.d.ts +4 -0
- package/dist/web/components/modal-provider.js +45 -0
- package/dist/web/components/modal-provider.js.map +1 -0
- package/dist/web/create-store.d.ts +29 -0
- package/dist/web/create-store.js +64 -0
- package/dist/web/create-store.js.map +1 -0
- package/dist/web/create-store.test.d.ts +1 -0
- package/dist/web/create-store.test.js +129 -0
- package/dist/web/create-store.test.js.map +1 -0
- package/dist/web/data-llm.d.ts +47 -0
- package/dist/web/data-llm.js +100 -0
- package/dist/web/data-llm.js.map +1 -0
- package/dist/web/data-llm.test.d.ts +1 -0
- package/dist/web/data-llm.test.js +142 -0
- package/dist/web/data-llm.test.js.map +1 -0
- package/dist/web/generate-helpers.d.ts +120 -0
- package/dist/web/generate-helpers.js +115 -0
- package/dist/web/generate-helpers.js.map +1 -0
- package/dist/web/generate-helpers.test-d.d.ts +1 -0
- package/dist/web/generate-helpers.test-d.js +211 -0
- package/dist/web/generate-helpers.test-d.js.map +1 -0
- package/dist/web/generate-helpers.test.d.ts +1 -0
- package/dist/web/generate-helpers.test.js +17 -0
- package/dist/web/generate-helpers.test.js.map +1 -0
- package/dist/web/helpers/state.d.ts +7 -0
- package/dist/web/helpers/state.js +45 -0
- package/dist/web/helpers/state.js.map +1 -0
- package/dist/web/helpers/state.test.d.ts +1 -0
- package/dist/web/helpers/state.test.js +53 -0
- package/dist/web/helpers/state.test.js.map +1 -0
- package/dist/web/hooks/index.d.ts +17 -0
- package/dist/web/hooks/index.js +18 -0
- package/dist/web/hooks/index.js.map +1 -0
- package/dist/web/hooks/test/utils.d.ts +20 -0
- package/dist/web/hooks/test/utils.js +75 -0
- package/dist/web/hooks/test/utils.js.map +1 -0
- package/dist/web/hooks/use-call-tool.d.ts +146 -0
- package/dist/web/hooks/use-call-tool.js +96 -0
- package/dist/web/hooks/use-call-tool.js.map +1 -0
- package/dist/web/hooks/use-call-tool.test-d.d.ts +1 -0
- package/dist/web/hooks/use-call-tool.test-d.js +104 -0
- package/dist/web/hooks/use-call-tool.test-d.js.map +1 -0
- package/dist/web/hooks/use-call-tool.test.d.ts +1 -0
- package/dist/web/hooks/use-call-tool.test.js +211 -0
- package/dist/web/hooks/use-call-tool.test.js.map +1 -0
- package/dist/web/hooks/use-display-mode.d.ts +24 -0
- package/dist/web/hooks/use-display-mode.js +29 -0
- package/dist/web/hooks/use-display-mode.js.map +1 -0
- package/dist/web/hooks/use-display-mode.test-d.d.ts +1 -0
- package/dist/web/hooks/use-display-mode.test-d.js +8 -0
- package/dist/web/hooks/use-display-mode.test-d.js.map +1 -0
- package/dist/web/hooks/use-display-mode.test.d.ts +1 -0
- package/dist/web/hooks/use-display-mode.test.js +41 -0
- package/dist/web/hooks/use-display-mode.test.js.map +1 -0
- package/dist/web/hooks/use-download.d.ts +5 -0
- package/dist/web/hooks/use-download.js +8 -0
- package/dist/web/hooks/use-download.js.map +1 -0
- package/dist/web/hooks/use-download.test.d.ts +1 -0
- package/dist/web/hooks/use-download.test.js +95 -0
- package/dist/web/hooks/use-download.test.js.map +1 -0
- package/dist/web/hooks/use-files.d.ts +39 -0
- package/dist/web/hooks/use-files.js +42 -0
- package/dist/web/hooks/use-files.js.map +1 -0
- package/dist/web/hooks/use-files.test.d.ts +1 -0
- package/dist/web/hooks/use-files.test.js +54 -0
- package/dist/web/hooks/use-files.test.js.map +1 -0
- package/dist/web/hooks/use-intent.d.ts +30 -0
- package/dist/web/hooks/use-intent.js +34 -0
- package/dist/web/hooks/use-intent.js.map +1 -0
- package/dist/web/hooks/use-intent.test.d.ts +1 -0
- package/dist/web/hooks/use-intent.test.js +85 -0
- package/dist/web/hooks/use-intent.test.js.map +1 -0
- package/dist/web/hooks/use-layout.d.ts +24 -0
- package/dist/web/hooks/use-layout.js +25 -0
- package/dist/web/hooks/use-layout.js.map +1 -0
- package/dist/web/hooks/use-layout.test.d.ts +1 -0
- package/dist/web/hooks/use-layout.test.js +96 -0
- package/dist/web/hooks/use-layout.test.js.map +1 -0
- package/dist/web/hooks/use-notify.d.ts +29 -0
- package/dist/web/hooks/use-notify.js +33 -0
- package/dist/web/hooks/use-notify.js.map +1 -0
- package/dist/web/hooks/use-notify.test.d.ts +1 -0
- package/dist/web/hooks/use-notify.test.js +105 -0
- package/dist/web/hooks/use-notify.test.js.map +1 -0
- package/dist/web/hooks/use-open-external.d.ts +20 -0
- package/dist/web/hooks/use-open-external.js +24 -0
- package/dist/web/hooks/use-open-external.js.map +1 -0
- package/dist/web/hooks/use-open-external.test.d.ts +1 -0
- package/dist/web/hooks/use-open-external.test.js +65 -0
- package/dist/web/hooks/use-open-external.test.js.map +1 -0
- package/dist/web/hooks/use-register-view-tool.d.ts +38 -0
- package/dist/web/hooks/use-register-view-tool.js +50 -0
- package/dist/web/hooks/use-register-view-tool.js.map +1 -0
- package/dist/web/hooks/use-request-close.d.ts +16 -0
- package/dist/web/hooks/use-request-close.js +21 -0
- package/dist/web/hooks/use-request-close.js.map +1 -0
- package/dist/web/hooks/use-request-close.test.d.ts +1 -0
- package/dist/web/hooks/use-request-close.test.js +52 -0
- package/dist/web/hooks/use-request-close.test.js.map +1 -0
- package/dist/web/hooks/use-request-modal.d.ts +24 -0
- package/dist/web/hooks/use-request-modal.js +31 -0
- package/dist/web/hooks/use-request-modal.js.map +1 -0
- package/dist/web/hooks/use-request-modal.test.d.ts +1 -0
- package/dist/web/hooks/use-request-modal.test.js +61 -0
- package/dist/web/hooks/use-request-modal.test.js.map +1 -0
- package/dist/web/hooks/use-request-size.d.ts +20 -0
- package/dist/web/hooks/use-request-size.js +24 -0
- package/dist/web/hooks/use-request-size.js.map +1 -0
- package/dist/web/hooks/use-request-size.test.d.ts +1 -0
- package/dist/web/hooks/use-request-size.test.js +65 -0
- package/dist/web/hooks/use-request-size.test.js.map +1 -0
- package/dist/web/hooks/use-send-follow-up-message.d.ts +19 -0
- package/dist/web/hooks/use-send-follow-up-message.js +25 -0
- package/dist/web/hooks/use-send-follow-up-message.js.map +1 -0
- package/dist/web/hooks/use-set-open-in-app-url.d.ts +18 -0
- package/dist/web/hooks/use-set-open-in-app-url.js +25 -0
- package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -0
- package/dist/web/hooks/use-set-open-in-app-url.test.d.ts +1 -0
- package/dist/web/hooks/use-set-open-in-app-url.test.js +43 -0
- package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -0
- package/dist/web/hooks/use-tool-info.d.ts +87 -0
- package/dist/web/hooks/use-tool-info.js +49 -0
- package/dist/web/hooks/use-tool-info.js.map +1 -0
- package/dist/web/hooks/use-tool-info.test-d.d.ts +1 -0
- package/dist/web/hooks/use-tool-info.test-d.js +91 -0
- package/dist/web/hooks/use-tool-info.test-d.js.map +1 -0
- package/dist/web/hooks/use-tool-info.test.d.ts +1 -0
- package/dist/web/hooks/use-tool-info.test.js +130 -0
- package/dist/web/hooks/use-tool-info.test.js.map +1 -0
- package/dist/web/hooks/use-user.d.ts +20 -0
- package/dist/web/hooks/use-user.js +37 -0
- package/dist/web/hooks/use-user.js.map +1 -0
- package/dist/web/hooks/use-user.test.d.ts +1 -0
- package/dist/web/hooks/use-user.test.js +122 -0
- package/dist/web/hooks/use-user.test.js.map +1 -0
- package/dist/web/hooks/use-view-state.d.ts +25 -0
- package/dist/web/hooks/use-view-state.js +32 -0
- package/dist/web/hooks/use-view-state.js.map +1 -0
- package/dist/web/hooks/use-view-state.test.d.ts +1 -0
- package/dist/web/hooks/use-view-state.test.js +177 -0
- package/dist/web/hooks/use-view-state.test.js.map +1 -0
- package/dist/web/index.d.ts +7 -0
- package/dist/web/index.js +8 -0
- package/dist/web/index.js.map +1 -0
- package/dist/web/mount-view.d.ts +20 -0
- package/dist/web/mount-view.js +46 -0
- package/dist/web/mount-view.js.map +1 -0
- package/dist/web/plugin/data-llm.test.d.ts +1 -0
- package/dist/web/plugin/data-llm.test.js +81 -0
- package/dist/web/plugin/data-llm.test.js.map +1 -0
- package/dist/web/plugin/plugin.d.ts +33 -0
- package/dist/web/plugin/plugin.js +189 -0
- package/dist/web/plugin/plugin.js.map +1 -0
- package/dist/web/plugin/scan-views.d.ts +16 -0
- package/dist/web/plugin/scan-views.js +88 -0
- package/dist/web/plugin/scan-views.js.map +1 -0
- package/dist/web/plugin/scan-views.test.d.ts +1 -0
- package/dist/web/plugin/scan-views.test.js +99 -0
- package/dist/web/plugin/scan-views.test.js.map +1 -0
- package/dist/web/plugin/transform-data-llm.d.ts +12 -0
- package/dist/web/plugin/transform-data-llm.js +96 -0
- package/dist/web/plugin/transform-data-llm.js.map +1 -0
- package/dist/web/plugin/transform-data-llm.test.d.ts +1 -0
- package/dist/web/plugin/transform-data-llm.test.js +81 -0
- package/dist/web/plugin/transform-data-llm.test.js.map +1 -0
- package/dist/web/plugin/validate-view.d.ts +1 -0
- package/dist/web/plugin/validate-view.js +9 -0
- package/dist/web/plugin/validate-view.js.map +1 -0
- package/dist/web/plugin/validate-view.test.d.ts +1 -0
- package/dist/web/plugin/validate-view.test.js +24 -0
- package/dist/web/plugin/validate-view.test.js.map +1 -0
- package/dist/web/proxy.d.ts +1 -0
- package/dist/web/proxy.js +52 -0
- package/dist/web/proxy.js.map +1 -0
- package/dist/web/types.d.ts +20 -0
- package/dist/web/types.js +2 -0
- package/dist/web/types.js.map +1 -0
- package/package.json +125 -0
- package/scripts/postinstall.mjs +45 -0
- package/tsconfig.base.json +36 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Alpic
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# enpilink
|
|
4
|
+
|
|
5
|
+
**The open, account-free full-stack framework for [MCP Apps](https://github.com/modelcontextprotocol/ext-apps) — and the ChatGPT Apps SDK.**
|
|
6
|
+
|
|
7
|
+
Build type-safe MCP servers whose tools render interactive **React views** inside
|
|
8
|
+
Claude, ChatGPT, VS Code, Goose, and any other MCP-Apps-compatible host.
|
|
9
|
+
|
|
10
|
+
<p>
|
|
11
|
+
<a href="https://github.com/enpitech/enpilink/blob/main/LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-8E2DE2.svg"></a>
|
|
12
|
+
<a href="https://github.com/modelcontextprotocol/ext-apps"><img alt="MCP Apps" src="https://img.shields.io/badge/MCP_Apps-compatible-4A00E0.svg"></a>
|
|
13
|
+
<img alt="Account-free" src="https://img.shields.io/badge/account-not_required-22c55e.svg">
|
|
14
|
+
<img alt="Tunnel: srv.us" src="https://img.shields.io/badge/tunnel-srv.us_(no_signup)-0ea5e9.svg">
|
|
15
|
+
<img alt="Interaction types" src="https://img.shields.io/badge/mcp--ui-tool_·_prompt_·_notify_·_intent-8E2DE2.svg">
|
|
16
|
+
<img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-strict-3178c6.svg?logo=typescript&logoColor=white">
|
|
17
|
+
<img alt="Node" src="https://img.shields.io/badge/node-%3E%3D22-339933.svg?logo=node.js&logoColor=white">
|
|
18
|
+
<a href="https://github.com/enpitech/enpilink/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/enpitech/enpilink/actions/workflows/ci.yml/badge.svg"></a>
|
|
19
|
+
<a href="https://github.com/enpitech/enpilink/pulls"><img alt="PRs welcome" src="https://img.shields.io/badge/PRs-welcome-FF941F.svg"></a>
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
<sub>a fork of <a href="https://github.com/alpic-ai/skybridge"><code>alpic-ai/skybridge</code></a> · powered by</sub>
|
|
23
|
+
|
|
24
|
+
<a href="https://enpitech.dev"><img src="docs/images/enpitech-logo.svg" alt="Enpitech" width="150"></a>
|
|
25
|
+
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Account-free by design
|
|
31
|
+
|
|
32
|
+
Local dev, public tunneling, and deploy all work with **no account, no token, and
|
|
33
|
+
no vendor lock-in**:
|
|
34
|
+
|
|
35
|
+
- **Account-free tunneling** via [srv.us](https://srv.us) — open and SSH-based, no
|
|
36
|
+
signup. `enpilink dev --tunnel` gives you a public `/mcp` URL in seconds and
|
|
37
|
+
auto-generates an SSH key at `~/.enpilink/id_ed25519` the first time.
|
|
38
|
+
- **No telemetry** — zero analytics, no network calls, no embedded keys.
|
|
39
|
+
- **Deploy anywhere** — `enpilink build` produces a standard Node server
|
|
40
|
+
(`node dist/__entry.js`); self-host on any platform or container.
|
|
41
|
+
- **All five mcp-ui interaction types** — `tool`, `prompt`, `link`, `intent`, and `notify`.
|
|
42
|
+
|
|
43
|
+
## MCP Apps compliance
|
|
44
|
+
|
|
45
|
+
enpilink is a compliant **MCP Apps** framework, built on the official
|
|
46
|
+
[`@modelcontextprotocol/ext-apps`](https://github.com/modelcontextprotocol/ext-apps)
|
|
47
|
+
extension (stable spec `2026-01-26`). It serves view resources for both runtimes
|
|
48
|
+
so the same view runs in either host:
|
|
49
|
+
|
|
50
|
+
- `ui://views/ext-apps/*` — MCP Apps (Claude, Goose, VS Code, …)
|
|
51
|
+
- `ui://views/apps-sdk/*` — ChatGPT Apps SDK
|
|
52
|
+
|
|
53
|
+
## The mcp-ui interaction types
|
|
54
|
+
|
|
55
|
+
An **interaction type** is one of the structured messages a view sends *back* to
|
|
56
|
+
its host. The [mcp-ui](https://mcpui.dev) standard defines **five**, and enpilink
|
|
57
|
+
supports all five (views send them through hooks, never raw `postMessage`):
|
|
58
|
+
|
|
59
|
+
| Type | Hook | Behavior |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| `tool` | `useCallTool` | real on both runtimes |
|
|
62
|
+
| `prompt` | `useSendFollowUpMessage` | real on both runtimes |
|
|
63
|
+
| `link` | `useOpenExternal` | real on both runtimes |
|
|
64
|
+
| `intent` | `useIntent` | no spec equivalent on either runtime; best-effort extension, may no-op on hosts that don't route it |
|
|
65
|
+
| `notify` | `useNotify` | real MCP `notifications/message` on MCP Apps; best-effort extension on the ChatGPT Apps SDK |
|
|
66
|
+
|
|
67
|
+
> These five are the standard's **view→host actions**. They're a subset of the
|
|
68
|
+
> full hook API below (the rest of the hooks *read* host context or *control*
|
|
69
|
+
> your own view). New to all this? See [`PRESENTATION.md`](PRESENTATION.md) for a
|
|
70
|
+
> plain-language, diagram-led tour.
|
|
71
|
+
|
|
72
|
+
`notify` and `intent` are guarded and additive: they never throw and degrade to
|
|
73
|
+
a no-op (or a log line) on hosts without support. See
|
|
74
|
+
[`docs/guides/interaction-types.mdx`](docs/guides/interaction-types.mdx) for the
|
|
75
|
+
full per-runtime matrix.
|
|
76
|
+
|
|
77
|
+
## All view hooks
|
|
78
|
+
|
|
79
|
+
Everything a view can do from inside the iframe — import from `enpilink/web`.
|
|
80
|
+
Hooks never touch raw `postMessage`; the bridge picks the right runtime call.
|
|
81
|
+
|
|
82
|
+
| Hook | What it does | Runtime |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| **Interaction** | | |
|
|
85
|
+
| `useCallTool` | Call a server tool from the view; returns `{ callTool, callToolAsync, data, status, error }` with pending/success/error state. | both |
|
|
86
|
+
| `useSendFollowUpMessage` | Send a text message to the model as a user follow-up turn (`prompt`). | both |
|
|
87
|
+
| `useNotify` | Surface a notification/status to the host: `notify({ message, level?, title?, data? })`. | both — real `notifications/message` on MCP Apps, best-effort on Apps SDK |
|
|
88
|
+
| `useIntent` | Express a high-level intent for the host to route: `sendIntent({ name, params? })`. | both — best-effort extension, may no-op |
|
|
89
|
+
| **Navigation / links** | | |
|
|
90
|
+
| `useOpenExternal` | Open a URL outside the iframe via the host (use instead of `window.open`). | both |
|
|
91
|
+
| `useSetOpenInAppUrl` | Override the URL the host's fullscreen "Open in app" affordance points to. | Apps SDK only (throws on MCP Apps) |
|
|
92
|
+
| `useRequestClose` | Ask the host to dismiss/close the view. | both |
|
|
93
|
+
| **Layout / display** | | |
|
|
94
|
+
| `useDisplayMode` | Read and request the display mode — `inline` / `pip` / `fullscreen`. | both |
|
|
95
|
+
| `useRequestModal` | Open the view in a host modal overlay; returns `{ isOpen, params, open }`. | both |
|
|
96
|
+
| `useRequestSize` | Ask the host to resize the iframe to fit your content. | both |
|
|
97
|
+
| `useLayout` | Read the visual environment — max height, safe-area insets, theme. | both |
|
|
98
|
+
| **Context / data** | | |
|
|
99
|
+
| `useToolInfo` | Read the typed `input` / `output` / metadata of the tool call that rendered this view. | both |
|
|
100
|
+
| `useViewState` | `[state, setState]` persisted on the host across remounts of the view. | both |
|
|
101
|
+
| `useUser` | Session-stable user/environment info (device type, hover/touch capability). | both |
|
|
102
|
+
| **Files** | | |
|
|
103
|
+
| `useFiles` | Host file operations — `upload`, `getDownloadUrl`, `selectFiles` (native picker). | Apps SDK only (throws on MCP Apps) |
|
|
104
|
+
| `useDownload` | Download an MCP `EmbeddedResource` / `ResourceLink`'s contents via the host. | both |
|
|
105
|
+
| **Advanced** | | |
|
|
106
|
+
| `useRegisterViewTool` | Let the view expose its own tool to the host/model (app-provided tool). | MCP Apps only (no-op on Apps SDK) |
|
|
107
|
+
|
|
108
|
+
> "both" = works on MCP Apps (Claude, Goose, VS Code…) and the ChatGPT Apps SDK.
|
|
109
|
+
> Apps-SDK-only hooks throw on MCP Apps; MCP-Apps-only hooks no-op on the Apps SDK.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Observability & Admin
|
|
114
|
+
|
|
115
|
+
enpilink ships an **opt-in** observability + admin layer — **off by default**,
|
|
116
|
+
with zero overhead and zero network when disabled (still no telemetry to us).
|
|
117
|
+
|
|
118
|
+
- **Observability** — set `ENPILINK_ANALYTICS=1` to record per-tool-call volume,
|
|
119
|
+
latency (p50/p95/p99), and error rate, viewable in the Console **Dashboard**
|
|
120
|
+
with a **live log stream**. Try it with demo data:
|
|
121
|
+
`enpilink dev --mock` (deterministic, in-memory, no real traffic). See
|
|
122
|
+
[`docs/guides/observability.mdx`](docs/guides/observability.mdx).
|
|
123
|
+
- **Configuration** — a typed config layer with **env > file > DB** precedence, a
|
|
124
|
+
**Configuration** admin tab for runtime settings, **env-only masked secrets**,
|
|
125
|
+
and a change **audit log**. See
|
|
126
|
+
[`docs/guides/configuration.mdx`](docs/guides/configuration.mdx).
|
|
127
|
+
- **Admin (production)** — expose the Dashboard + Configuration in prod with
|
|
128
|
+
`enpilink start --admin` + `ENPILINK_ADMIN_TOKEN` (refuses to start without a
|
|
129
|
+
token). Two-tier auth keeps `/mcp` and the SPA shell public while gating the
|
|
130
|
+
data APIs behind a static bearer token; for SSO, front it with a reverse proxy
|
|
131
|
+
(Cloudflare Access / oauth2-proxy / Tailscale) or self-hosted OIDC. See
|
|
132
|
+
[`docs/guides/admin.mdx`](docs/guides/admin.mdx).
|
|
133
|
+
- **Storage** — pluggable adapters: `memory` (dev), `sqlite` (prod default,
|
|
134
|
+
`ENPILINK_DB_PATH`), `postgres` (`ENPILINK_DB_URL`/`DATABASE_URL`/`PG*`), plus
|
|
135
|
+
`registerStorageAdapter` for custom backends, and optional **OpenTelemetry**
|
|
136
|
+
metrics export (`ENPILINK_OTEL=1` + `OTEL_EXPORTER_OTLP_ENDPOINT`). See
|
|
137
|
+
[`docs/guides/storage.mdx`](docs/guides/storage.mdx).
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Documentation
|
|
142
|
+
|
|
143
|
+
**New here?** Read [`PRESENTATION.md`](PRESENTATION.md) first — a plain-language,
|
|
144
|
+
diagram-led tour of the whole platform (what it solves, the standards, the
|
|
145
|
+
technology, and how interaction types relate to hooks). No prior knowledge needed.
|
|
146
|
+
|
|
147
|
+
There's **no hosted docs site yet** — the full docs run locally with
|
|
148
|
+
[Mintlify](https://mintlify.com):
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
pnpm install
|
|
152
|
+
pnpm docs:dev # serves the docs at http://localhost:3000
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
What's inside [`docs/`](docs):
|
|
156
|
+
|
|
157
|
+
- **API reference** ([`docs/api-reference/`](docs/api-reference)) — a page per
|
|
158
|
+
hook and core API (`useCallTool`, `useNotify`, `useViewState`, `registerTool`,
|
|
159
|
+
…), each with the signature, **a runnable example**, and runtime support. This
|
|
160
|
+
is the "what can I actually do with this hook" reference.
|
|
161
|
+
- **Guides** ([`docs/guides/`](docs/guides)) — task-oriented: communicating with
|
|
162
|
+
the model, managing state, host-environment context, fetching data, the
|
|
163
|
+
interaction types, and the observability / configuration / admin / storage
|
|
164
|
+
layer.
|
|
165
|
+
- **Concepts & fundamentals** — MCP Apps vs the Apps SDK, write-once-run-everywhere,
|
|
166
|
+
type safety, and data flow.
|
|
167
|
+
- **Quickstart** — create a new app, add to an existing server, deploy, migrate.
|
|
168
|
+
|
|
169
|
+
> Tip: you can also read any page directly as Markdown in [`docs/`](docs) on
|
|
170
|
+
> GitHub — e.g. [`docs/api-reference/use-notify.mdx`](docs/api-reference/use-notify.mdx).
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Quickstart
|
|
175
|
+
|
|
176
|
+
### Prerequisites
|
|
177
|
+
|
|
178
|
+
- **Node.js ≥ 22**
|
|
179
|
+
- `ssh` (ships with macOS/Linux) — only needed for `--tunnel`
|
|
180
|
+
|
|
181
|
+
### Run the built-in kitchen-sink demo
|
|
182
|
+
|
|
183
|
+
The fastest way to see everything is the bundled **kitchen-sink** showcase
|
|
184
|
+
(a fictional store, *Northwind*): 9 tools, 9 views, all 4 interaction types,
|
|
185
|
+
every host hook, deterministic mock data.
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
git clone https://github.com/enpitech/enpilink
|
|
189
|
+
cd enpilink && pnpm install && pnpm run build
|
|
190
|
+
|
|
191
|
+
cd examples/kitchen-sink
|
|
192
|
+
pnpm dev # Console + HMR at http://localhost:3000/
|
|
193
|
+
pnpm dev:tunnel # opens an account-free srv.us tunnel and prints a public /mcp URL
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Then connect it to Claude:
|
|
197
|
+
|
|
198
|
+
1. Copy the printed `https://<hash>.srv.us/mcp` URL.
|
|
199
|
+
2. In Claude → **Settings → Connectors → Add custom connector**, paste that URL.
|
|
200
|
+
3. Paste the contents of
|
|
201
|
+
[`examples/kitchen-sink/specs/SYSTEM_PROMPT.md`](examples/kitchen-sink/specs/SYSTEM_PROMPT.md)
|
|
202
|
+
into your Claude **project instructions** (MCP can't set a host system prompt,
|
|
203
|
+
so this tells the assistant which tools to call).
|
|
204
|
+
|
|
205
|
+
### Scaffold a new app
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
npm create enpilink@latest my-app
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
> **POC distribution caveat.** `enpilink` and `@enpilink/console` are not yet
|
|
212
|
+
> published to npm, so a freshly scaffolded app's `npm install` will fail on the
|
|
213
|
+
> `workspace:*` ranges in the templates. For real distribution, publish both
|
|
214
|
+
> packages to npm and run `node scripts/bump.js <version>` to rewrite the
|
|
215
|
+
> templates' `workspace:*` ranges to `^<version>`. Until then, scaffold inside
|
|
216
|
+
> this monorepo (the templates resolve via the workspace) or use local
|
|
217
|
+
> `pnpm pack` tarballs. See [Status](#status) below.
|
|
218
|
+
|
|
219
|
+
The account-free tunnel under the hood is just one SSH command:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
ssh srv.us -R 1:localhost:<port>
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
enpilink wraps this with auto key-gen (`~/.enpilink/id_ed25519`), URL parsing,
|
|
226
|
+
and auto-reconnect.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## CLI
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
enpilink dev [--tunnel] [-p <port>] [--open] [--mock] # dev server + Console + HMR (alias: enpi)
|
|
234
|
+
enpilink build # compile server + views → dist/
|
|
235
|
+
enpilink start [--admin] # run the production build (node dist/__entry.js)
|
|
236
|
+
enpilink create [dir] # scaffold a new app (passthrough to create-enpilink)
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Production gotcha
|
|
240
|
+
|
|
241
|
+
The production entry reads the **`__PORT`** environment variable (NOT `PORT`),
|
|
242
|
+
defaulting to `3000`:
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
__PORT=8080 node dist/__entry.js
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
`enpilink start` sets `__PORT` for you. `enpilink build` also rewrites server
|
|
249
|
+
`@/…` path aliases automatically, so you do **not** need `tsc-alias` in your own
|
|
250
|
+
build scripts.
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Repo layout
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
enpilink/
|
|
258
|
+
├── packages/
|
|
259
|
+
│ ├── core/ → npm "enpilink": server framework + React hooks + Vite plugin + CLI (oclif + Ink)
|
|
260
|
+
│ ├── console/ → "@enpilink/console": dashboard / config / playground / docs web UI
|
|
261
|
+
│ └── create-enpilink/ → "create-enpilink": scaffolder (templates: blank, demo)
|
|
262
|
+
├── examples/
|
|
263
|
+
│ ├── kitchen-sink/ → the all-features showcase ("Northwind"); basis of the demo template
|
|
264
|
+
│ └── manifest-ui/ → minimal single-view smoke-test example
|
|
265
|
+
├── docs/ → Mintlify documentation
|
|
266
|
+
├── skills/ → agent skill for building enpilink apps
|
|
267
|
+
└── scripts/ → version bump / overrides helpers
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Status
|
|
271
|
+
|
|
272
|
+
This is a POC fork. Today:
|
|
273
|
+
|
|
274
|
+
- ✅ Local dev, Console, HMR, build, and self-host all work account-free.
|
|
275
|
+
- ✅ The account-free **srv.us** tunnel is live-verified end-to-end (the printed
|
|
276
|
+
`/mcp` URL round-trips over a real public tunnel and survives reconnects).
|
|
277
|
+
- ⏳ **Real npm distribution** requires publishing `enpilink` + `@enpilink/console`
|
|
278
|
+
to npm, then running `node scripts/bump.js <version>`. Until then,
|
|
279
|
+
`npm create enpilink` is workspace-linked (works inside this repo / via local
|
|
280
|
+
tarballs, not from a bare `npm install`).
|
|
281
|
+
|
|
282
|
+
## Attribution & license
|
|
283
|
+
|
|
284
|
+
enpilink is released under the [MIT License](LICENSE). It is forked from
|
|
285
|
+
[`alpic-ai/skybridge`](https://github.com/alpic-ai/skybridge) (MIT); the original
|
|
286
|
+
copyright is retained in `LICENSE`, and the fork's changes are summarized in
|
|
287
|
+
[`NOTICE`](NOTICE).
|
|
288
|
+
|
|
289
|
+
Built and maintained by the [Enpitech](https://enpitech.dev) team.
|
package/bin/run.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const ENTRY_WRAPPER_CONTENT = "import { __setBuildManifest } from \"enpilink/server\";\nimport manifest from \"./vite-manifest.js\";\n\n__setBuildManifest(manifest);\n\nconst userMod = await import(\"./server.js\");\nexport default userMod.default;\n";
|
|
2
|
+
export declare function emitEntryWrapper(distDir: string): void;
|
|
3
|
+
export declare function emitManifestModule(manifestPath: string, outPath: string): void;
|
|
4
|
+
export declare function rewriteServerAliases(root: string): Promise<void>;
|
|
5
|
+
export declare const VERCEL_FUNCTION_NAME = "mcp";
|
|
6
|
+
export declare const VERCEL_CONFIG: unknown;
|
|
7
|
+
export declare const VERCEL_VC_CONFIG: unknown;
|
|
8
|
+
export declare function emitVercelBuildOutput(root: string): Promise<void>;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync, } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
// Primes the manifest in enpilink's module scope, then dynamically imports
|
|
4
|
+
// `./server.js` so user code runs *after* the side channel is set. The
|
|
5
|
+
// dynamic import is load-bearing: a static `export { default } from ...` is
|
|
6
|
+
// hoisted with the rest of the static graph and would evaluate `server.js`
|
|
7
|
+
// before `__setBuildManifest` runs.
|
|
8
|
+
export const ENTRY_WRAPPER_CONTENT = `import { __setBuildManifest } from "enpilink/server";
|
|
9
|
+
import manifest from "./vite-manifest.js";
|
|
10
|
+
|
|
11
|
+
__setBuildManifest(manifest);
|
|
12
|
+
|
|
13
|
+
const userMod = await import("./server.js");
|
|
14
|
+
export default userMod.default;
|
|
15
|
+
`;
|
|
16
|
+
export function emitEntryWrapper(distDir) {
|
|
17
|
+
writeFileSync(path.join(distDir, "__entry.js"), ENTRY_WRAPPER_CONTENT);
|
|
18
|
+
}
|
|
19
|
+
export function emitManifestModule(manifestPath, outPath) {
|
|
20
|
+
const manifest = readFileSync(manifestPath, "utf-8");
|
|
21
|
+
writeFileSync(outPath, `export default ${manifest};\n`);
|
|
22
|
+
}
|
|
23
|
+
// Rewrites TypeScript path aliases (e.g. `@/data` → `./data`) in the emitted
|
|
24
|
+
// server JS under `dist/`. `tsc` itself does NOT rewrite path aliases in the
|
|
25
|
+
// output, so a server that imports via `@/…` would throw ERR_MODULE_NOT_FOUND
|
|
26
|
+
// at `node dist/__entry.js`. We run tsc-alias programmatically against the
|
|
27
|
+
// project's tsconfig so `enpilink build` produces a runnable server regardless
|
|
28
|
+
// of whether the user uses path aliases — no `tsc-alias` in their own scripts.
|
|
29
|
+
//
|
|
30
|
+
// Safe to run unconditionally: tsc-alias uses TypeScript's own config parser
|
|
31
|
+
// and is a no-op when the project declares no `paths`. We only require a
|
|
32
|
+
// tsconfig.json to exist (it always does for an enpilink app).
|
|
33
|
+
export async function rewriteServerAliases(root) {
|
|
34
|
+
const configFile = path.join(root, "tsconfig.json");
|
|
35
|
+
if (!existsSync(configFile)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const { replaceTscAliasPaths } = await import("tsc-alias");
|
|
39
|
+
await replaceTscAliasPaths({
|
|
40
|
+
configFile,
|
|
41
|
+
// The server's compiled JS lives in `dist/` (tsc `outDir`); rewrite aliases
|
|
42
|
+
// to relative imports there.
|
|
43
|
+
outDir: path.join(root, "dist"),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
export const VERCEL_FUNCTION_NAME = "mcp";
|
|
47
|
+
export const VERCEL_CONFIG = {
|
|
48
|
+
version: 3,
|
|
49
|
+
routes: [
|
|
50
|
+
{
|
|
51
|
+
src: "/assets/(.*)",
|
|
52
|
+
headers: { "Access-Control-Allow-Origin": "*" },
|
|
53
|
+
continue: true,
|
|
54
|
+
},
|
|
55
|
+
{ handle: "filesystem" },
|
|
56
|
+
{ src: "/(.*)", dest: `/${VERCEL_FUNCTION_NAME}` },
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
export const VERCEL_VC_CONFIG = {
|
|
60
|
+
runtime: "nodejs22.x",
|
|
61
|
+
handler: "index.js",
|
|
62
|
+
launcherType: "Nodejs",
|
|
63
|
+
shouldAddHelpers: true,
|
|
64
|
+
};
|
|
65
|
+
// Emit a Build Output API tree under `.vercel/output/`. Bundling the server
|
|
66
|
+
// with esbuild produces a self-contained function bundle, so we don't ship
|
|
67
|
+
// `node_modules` and don't touch tracked paths like `api/` or `public/`.
|
|
68
|
+
//
|
|
69
|
+
// Entry is `dist/__entry.js` — the wrapper that primes the Vite manifest via
|
|
70
|
+
// `__setBuildManifest` before importing user code. Bundling `dist/server.js`
|
|
71
|
+
// directly would skip that priming and 500 on view resource reads when the
|
|
72
|
+
// function falls back to `readFileSync('dist/assets/.vite/manifest.json')`
|
|
73
|
+
// (Vercel functions don't ship `dist/`).
|
|
74
|
+
export async function emitVercelBuildOutput(root) {
|
|
75
|
+
const outputDir = path.join(root, ".vercel", "output");
|
|
76
|
+
const funcDir = path.join(outputDir, "functions", `${VERCEL_FUNCTION_NAME}.func`);
|
|
77
|
+
const staticAssetsDir = path.join(outputDir, "static", "assets");
|
|
78
|
+
rmSync(outputDir, { recursive: true, force: true });
|
|
79
|
+
mkdirSync(funcDir, { recursive: true });
|
|
80
|
+
const { build } = await import("esbuild");
|
|
81
|
+
await build({
|
|
82
|
+
entryPoints: [path.join(root, "dist", "__entry.js")],
|
|
83
|
+
bundle: true,
|
|
84
|
+
platform: "node",
|
|
85
|
+
target: "node22",
|
|
86
|
+
format: "esm",
|
|
87
|
+
outfile: path.join(funcDir, "index.js"),
|
|
88
|
+
// Lets esbuild DCE dev-only branches that pull in vite/devtools.
|
|
89
|
+
define: { "process.env.NODE_ENV": '"production"' },
|
|
90
|
+
// Dev-only deps reachable from re-exports; safe to leave unresolved since
|
|
91
|
+
// the code paths that touch them are eliminated by the NODE_ENV define.
|
|
92
|
+
external: ["vite", "@enpilink/console"],
|
|
93
|
+
banner: {
|
|
94
|
+
// ESM bundles miss CJS interop globals that some deps reach for.
|
|
95
|
+
js: "import{createRequire}from'node:module';const require=createRequire(import.meta.url);",
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
writeFileSync(path.join(funcDir, ".vc-config.json"), `${JSON.stringify(VERCEL_VC_CONFIG, null, 2)}\n`);
|
|
99
|
+
writeFileSync(path.join(funcDir, "package.json"), `${JSON.stringify({ type: "module" }, null, 2)}\n`);
|
|
100
|
+
cpSync(path.join(root, "dist", "assets"), staticAssetsDir, {
|
|
101
|
+
recursive: true,
|
|
102
|
+
});
|
|
103
|
+
writeFileSync(path.join(outputDir, "config.json"), `${JSON.stringify(VERCEL_CONFIG, null, 2)}\n`);
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=build-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-helpers.js","sourceRoot":"","sources":["../../src/cli/build-helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n cpSync,\n existsSync,\n mkdirSync,\n readFileSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport path from \"node:path\";\n\n// Primes the manifest in enpilink's module scope, then dynamically imports\n// `./server.js` so user code runs *after* the side channel is set. The\n// dynamic import is load-bearing: a static `export { default } from ...` is\n// hoisted with the rest of the static graph and would evaluate `server.js`\n// before `__setBuildManifest` runs.\nexport const ENTRY_WRAPPER_CONTENT = `import { __setBuildManifest } from \"enpilink/server\";\nimport manifest from \"./vite-manifest.js\";\n\n__setBuildManifest(manifest);\n\nconst userMod = await import(\"./server.js\");\nexport default userMod.default;\n`;\n\nexport function emitEntryWrapper(distDir: string): void {\n writeFileSync(path.join(distDir, \"__entry.js\"), ENTRY_WRAPPER_CONTENT);\n}\n\nexport function emitManifestModule(\n manifestPath: string,\n outPath: string,\n): void {\n const manifest = readFileSync(manifestPath, \"utf-8\");\n writeFileSync(outPath, `export default ${manifest};\\n`);\n}\n\n// Rewrites TypeScript path aliases (e.g. `@/data` → `./data`) in the emitted\n// server JS under `dist/`. `tsc` itself does NOT rewrite path aliases in the\n// output, so a server that imports via `@/…` would throw ERR_MODULE_NOT_FOUND\n// at `node dist/__entry.js`. We run tsc-alias programmatically against the\n// project's tsconfig so `enpilink build` produces a runnable server regardless\n// of whether the user uses path aliases — no `tsc-alias` in their own scripts.\n//\n// Safe to run unconditionally: tsc-alias uses TypeScript's own config parser\n// and is a no-op when the project declares no `paths`. We only require a\n// tsconfig.json to exist (it always does for an enpilink app).\nexport async function rewriteServerAliases(root: string): Promise<void> {\n const configFile = path.join(root, \"tsconfig.json\");\n if (!existsSync(configFile)) {\n return;\n }\n const { replaceTscAliasPaths } = await import(\"tsc-alias\");\n await replaceTscAliasPaths({\n configFile,\n // The server's compiled JS lives in `dist/` (tsc `outDir`); rewrite aliases\n // to relative imports there.\n outDir: path.join(root, \"dist\"),\n });\n}\n\nexport const VERCEL_FUNCTION_NAME = \"mcp\";\n\nexport const VERCEL_CONFIG: unknown = {\n version: 3,\n routes: [\n {\n src: \"/assets/(.*)\",\n headers: { \"Access-Control-Allow-Origin\": \"*\" },\n continue: true,\n },\n { handle: \"filesystem\" },\n { src: \"/(.*)\", dest: `/${VERCEL_FUNCTION_NAME}` },\n ],\n};\n\nexport const VERCEL_VC_CONFIG: unknown = {\n runtime: \"nodejs22.x\",\n handler: \"index.js\",\n launcherType: \"Nodejs\",\n shouldAddHelpers: true,\n};\n\n// Emit a Build Output API tree under `.vercel/output/`. Bundling the server\n// with esbuild produces a self-contained function bundle, so we don't ship\n// `node_modules` and don't touch tracked paths like `api/` or `public/`.\n//\n// Entry is `dist/__entry.js` — the wrapper that primes the Vite manifest via\n// `__setBuildManifest` before importing user code. Bundling `dist/server.js`\n// directly would skip that priming and 500 on view resource reads when the\n// function falls back to `readFileSync('dist/assets/.vite/manifest.json')`\n// (Vercel functions don't ship `dist/`).\nexport async function emitVercelBuildOutput(root: string): Promise<void> {\n const outputDir = path.join(root, \".vercel\", \"output\");\n const funcDir = path.join(\n outputDir,\n \"functions\",\n `${VERCEL_FUNCTION_NAME}.func`,\n );\n const staticAssetsDir = path.join(outputDir, \"static\", \"assets\");\n\n rmSync(outputDir, { recursive: true, force: true });\n mkdirSync(funcDir, { recursive: true });\n\n const { build } = await import(\"esbuild\");\n await build({\n entryPoints: [path.join(root, \"dist\", \"__entry.js\")],\n bundle: true,\n platform: \"node\",\n target: \"node22\",\n format: \"esm\",\n outfile: path.join(funcDir, \"index.js\"),\n // Lets esbuild DCE dev-only branches that pull in vite/devtools.\n define: { \"process.env.NODE_ENV\": '\"production\"' },\n // Dev-only deps reachable from re-exports; safe to leave unresolved since\n // the code paths that touch them are eliminated by the NODE_ENV define.\n external: [\"vite\", \"@enpilink/console\"],\n banner: {\n // ESM bundles miss CJS interop globals that some deps reach for.\n js: \"import{createRequire}from'node:module';const require=createRequire(import.meta.url);\",\n },\n });\n\n writeFileSync(\n path.join(funcDir, \".vc-config.json\"),\n `${JSON.stringify(VERCEL_VC_CONFIG, null, 2)}\\n`,\n );\n writeFileSync(\n path.join(funcDir, \"package.json\"),\n `${JSON.stringify({ type: \"module\" }, null, 2)}\\n`,\n );\n\n cpSync(path.join(root, \"dist\", \"assets\"), staticAssetsDir, {\n recursive: true,\n });\n\n writeFileSync(\n path.join(outputDir, \"config.json\"),\n `${JSON.stringify(VERCEL_CONFIG, null, 2)}\\n`,\n );\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
// esbuild's invariant check on TextEncoder/Uint8Array trips jsdom's polyfill.
|
|
3
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync, } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { describe, expect, it } from "vitest";
|
|
7
|
+
import { ENTRY_WRAPPER_CONTENT, emitEntryWrapper, emitManifestModule, emitVercelBuildOutput, rewriteServerAliases, VERCEL_CONFIG, VERCEL_VC_CONFIG, } from "./build-helpers.js";
|
|
8
|
+
function mkTmp(prefix = "enpilink-build-helpers-") {
|
|
9
|
+
return mkdtempSync(path.join(tmpdir(), prefix));
|
|
10
|
+
}
|
|
11
|
+
describe("emitEntryWrapper", () => {
|
|
12
|
+
it("writes dist/__entry.js that primes the manifest before importing user code", () => {
|
|
13
|
+
const dir = mkTmp();
|
|
14
|
+
emitEntryWrapper(dir);
|
|
15
|
+
const out = readFileSync(path.join(dir, "__entry.js"), "utf-8");
|
|
16
|
+
expect(out).toBe(ENTRY_WRAPPER_CONTENT);
|
|
17
|
+
expect(out).toContain('import { __setBuildManifest } from "enpilink/server"');
|
|
18
|
+
expect(out).toContain('import manifest from "./vite-manifest.js"');
|
|
19
|
+
expect(out).toContain("__setBuildManifest(manifest)");
|
|
20
|
+
// Dynamic import is load-bearing: `server.js` must evaluate after the
|
|
21
|
+
// setter runs, so a static re-export wouldn't work.
|
|
22
|
+
expect(out).toContain('await import("./server.js")');
|
|
23
|
+
expect(out).toContain("export default userMod.default");
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
describe("emitManifestModule", () => {
|
|
27
|
+
it("inlines the JSON manifest as an ESM default export", () => {
|
|
28
|
+
const dir = mkTmp();
|
|
29
|
+
const inPath = path.join(dir, "manifest.json");
|
|
30
|
+
const outPath = path.join(dir, "vite-manifest.js");
|
|
31
|
+
const manifest = { "src/views/foo.tsx": { file: "assets/foo-abc.js" } };
|
|
32
|
+
writeFileSync(inPath, JSON.stringify(manifest));
|
|
33
|
+
emitManifestModule(inPath, outPath);
|
|
34
|
+
const out = readFileSync(outPath, "utf-8");
|
|
35
|
+
expect(out.startsWith("export default ")).toBe(true);
|
|
36
|
+
const literal = out
|
|
37
|
+
.slice("export default ".length)
|
|
38
|
+
.trim()
|
|
39
|
+
.replace(/;$/, "");
|
|
40
|
+
expect(JSON.parse(literal)).toEqual(manifest);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
describe("rewriteServerAliases", () => {
|
|
44
|
+
it("rewrites `@/` path aliases to relative imports in dist server JS", async () => {
|
|
45
|
+
const root = mkTmp();
|
|
46
|
+
mkdirSync(path.join(root, "src", "data"), { recursive: true });
|
|
47
|
+
mkdirSync(path.join(root, "dist", "data"), { recursive: true });
|
|
48
|
+
writeFileSync(path.join(root, "tsconfig.json"), JSON.stringify({
|
|
49
|
+
compilerOptions: {
|
|
50
|
+
outDir: "./dist",
|
|
51
|
+
rootDir: "./src",
|
|
52
|
+
paths: { "@/*": ["./src/*"] },
|
|
53
|
+
},
|
|
54
|
+
include: ["src"],
|
|
55
|
+
}));
|
|
56
|
+
// tsc-alias resolves aliases against the *output* tree, so the target must
|
|
57
|
+
// exist in dist/ (it normally does — tsc emits it).
|
|
58
|
+
writeFileSync(path.join(root, "dist", "data", "index.js"), "export {};\n");
|
|
59
|
+
writeFileSync(path.join(root, "dist", "server.js"), 'import { TODAY } from "@/data/index.js";\nexport default TODAY;\n');
|
|
60
|
+
await rewriteServerAliases(root);
|
|
61
|
+
const out = readFileSync(path.join(root, "dist", "server.js"), "utf-8");
|
|
62
|
+
expect(out).not.toContain("@/data");
|
|
63
|
+
expect(out).toContain("./data/index.js");
|
|
64
|
+
});
|
|
65
|
+
it("is a no-op when the project declares no `paths`", async () => {
|
|
66
|
+
const root = mkTmp();
|
|
67
|
+
mkdirSync(path.join(root, "dist"), { recursive: true });
|
|
68
|
+
writeFileSync(path.join(root, "tsconfig.json"), JSON.stringify({ compilerOptions: { outDir: "./dist" } }));
|
|
69
|
+
const original = 'import { x } from "./local.js";\n';
|
|
70
|
+
writeFileSync(path.join(root, "dist", "server.js"), original);
|
|
71
|
+
await expect(rewriteServerAliases(root)).resolves.toBeUndefined();
|
|
72
|
+
expect(readFileSync(path.join(root, "dist", "server.js"), "utf-8")).toBe(original);
|
|
73
|
+
});
|
|
74
|
+
it("does nothing when there is no tsconfig.json", async () => {
|
|
75
|
+
const root = mkTmp();
|
|
76
|
+
await expect(rewriteServerAliases(root)).resolves.toBeUndefined();
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
describe("emitVercelBuildOutput", () => {
|
|
80
|
+
it("emits a Build Output API tree with bundled function and static assets", async () => {
|
|
81
|
+
const root = mkTmp();
|
|
82
|
+
mkdirSync(path.join(root, "dist", "assets"), { recursive: true });
|
|
83
|
+
writeFileSync(path.join(root, "dist", "server.js"), "export default function handler(_req, res) { res.end('ok'); }\n");
|
|
84
|
+
// Minimal `dist/__entry.js` (the real wrapper imports `enpilink/server`,
|
|
85
|
+
// which isn't resolvable in this test's tmp dir — the function-bundling
|
|
86
|
+
// contract we care about here is just "bundle whatever `__entry.js`
|
|
87
|
+
// imports into a single function file").
|
|
88
|
+
writeFileSync(path.join(root, "dist", "__entry.js"), "const userMod = await import('./server.js');\nexport default userMod.default;\n");
|
|
89
|
+
writeFileSync(path.join(root, "dist", "assets", "view-abc.js"), "/* bundled view */\n");
|
|
90
|
+
await emitVercelBuildOutput(root);
|
|
91
|
+
const outputDir = path.join(root, ".vercel", "output");
|
|
92
|
+
const funcDir = path.join(outputDir, "functions", "mcp.func");
|
|
93
|
+
expect(existsSync(path.join(funcDir, "index.js"))).toBe(true);
|
|
94
|
+
expect(JSON.parse(readFileSync(path.join(funcDir, ".vc-config.json"), "utf-8"))).toEqual(VERCEL_VC_CONFIG);
|
|
95
|
+
expect(JSON.parse(readFileSync(path.join(funcDir, "package.json"), "utf-8"))).toEqual({ type: "module" });
|
|
96
|
+
expect(JSON.parse(readFileSync(path.join(outputDir, "config.json"), "utf-8"))).toEqual(VERCEL_CONFIG);
|
|
97
|
+
expect(readFileSync(path.join(outputDir, "static", "assets", "view-abc.js"), "utf-8")).toContain("bundled view");
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
//# sourceMappingURL=build-helpers.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-helpers.test.js","sourceRoot":"","sources":["../../src/cli/build-helpers.test.ts"],"names":[],"mappings":"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","sourcesContent":["// @vitest-environment node\n// esbuild's invariant check on TextEncoder/Uint8Array trips jsdom's polyfill.\nimport {\n existsSync,\n mkdirSync,\n mkdtempSync,\n readFileSync,\n writeFileSync,\n} from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport { describe, expect, it } from \"vitest\";\nimport {\n ENTRY_WRAPPER_CONTENT,\n emitEntryWrapper,\n emitManifestModule,\n emitVercelBuildOutput,\n rewriteServerAliases,\n VERCEL_CONFIG,\n VERCEL_VC_CONFIG,\n} from \"./build-helpers.js\";\n\nfunction mkTmp(prefix = \"enpilink-build-helpers-\") {\n return mkdtempSync(path.join(tmpdir(), prefix));\n}\n\ndescribe(\"emitEntryWrapper\", () => {\n it(\"writes dist/__entry.js that primes the manifest before importing user code\", () => {\n const dir = mkTmp();\n emitEntryWrapper(dir);\n const out = readFileSync(path.join(dir, \"__entry.js\"), \"utf-8\");\n expect(out).toBe(ENTRY_WRAPPER_CONTENT);\n expect(out).toContain(\n 'import { __setBuildManifest } from \"enpilink/server\"',\n );\n expect(out).toContain('import manifest from \"./vite-manifest.js\"');\n expect(out).toContain(\"__setBuildManifest(manifest)\");\n // Dynamic import is load-bearing: `server.js` must evaluate after the\n // setter runs, so a static re-export wouldn't work.\n expect(out).toContain('await import(\"./server.js\")');\n expect(out).toContain(\"export default userMod.default\");\n });\n});\n\ndescribe(\"emitManifestModule\", () => {\n it(\"inlines the JSON manifest as an ESM default export\", () => {\n const dir = mkTmp();\n const inPath = path.join(dir, \"manifest.json\");\n const outPath = path.join(dir, \"vite-manifest.js\");\n const manifest = { \"src/views/foo.tsx\": { file: \"assets/foo-abc.js\" } };\n writeFileSync(inPath, JSON.stringify(manifest));\n emitManifestModule(inPath, outPath);\n const out = readFileSync(outPath, \"utf-8\");\n expect(out.startsWith(\"export default \")).toBe(true);\n const literal = out\n .slice(\"export default \".length)\n .trim()\n .replace(/;$/, \"\");\n expect(JSON.parse(literal)).toEqual(manifest);\n });\n});\n\ndescribe(\"rewriteServerAliases\", () => {\n it(\"rewrites `@/` path aliases to relative imports in dist server JS\", async () => {\n const root = mkTmp();\n mkdirSync(path.join(root, \"src\", \"data\"), { recursive: true });\n mkdirSync(path.join(root, \"dist\", \"data\"), { recursive: true });\n writeFileSync(\n path.join(root, \"tsconfig.json\"),\n JSON.stringify({\n compilerOptions: {\n outDir: \"./dist\",\n rootDir: \"./src\",\n paths: { \"@/*\": [\"./src/*\"] },\n },\n include: [\"src\"],\n }),\n );\n // tsc-alias resolves aliases against the *output* tree, so the target must\n // exist in dist/ (it normally does — tsc emits it).\n writeFileSync(path.join(root, \"dist\", \"data\", \"index.js\"), \"export {};\\n\");\n writeFileSync(\n path.join(root, \"dist\", \"server.js\"),\n 'import { TODAY } from \"@/data/index.js\";\\nexport default TODAY;\\n',\n );\n\n await rewriteServerAliases(root);\n\n const out = readFileSync(path.join(root, \"dist\", \"server.js\"), \"utf-8\");\n expect(out).not.toContain(\"@/data\");\n expect(out).toContain(\"./data/index.js\");\n });\n\n it(\"is a no-op when the project declares no `paths`\", async () => {\n const root = mkTmp();\n mkdirSync(path.join(root, \"dist\"), { recursive: true });\n writeFileSync(\n path.join(root, \"tsconfig.json\"),\n JSON.stringify({ compilerOptions: { outDir: \"./dist\" } }),\n );\n const original = 'import { x } from \"./local.js\";\\n';\n writeFileSync(path.join(root, \"dist\", \"server.js\"), original);\n\n await expect(rewriteServerAliases(root)).resolves.toBeUndefined();\n expect(readFileSync(path.join(root, \"dist\", \"server.js\"), \"utf-8\")).toBe(\n original,\n );\n });\n\n it(\"does nothing when there is no tsconfig.json\", async () => {\n const root = mkTmp();\n await expect(rewriteServerAliases(root)).resolves.toBeUndefined();\n });\n});\n\ndescribe(\"emitVercelBuildOutput\", () => {\n it(\"emits a Build Output API tree with bundled function and static assets\", async () => {\n const root = mkTmp();\n mkdirSync(path.join(root, \"dist\", \"assets\"), { recursive: true });\n writeFileSync(\n path.join(root, \"dist\", \"server.js\"),\n \"export default function handler(_req, res) { res.end('ok'); }\\n\",\n );\n // Minimal `dist/__entry.js` (the real wrapper imports `enpilink/server`,\n // which isn't resolvable in this test's tmp dir — the function-bundling\n // contract we care about here is just \"bundle whatever `__entry.js`\n // imports into a single function file\").\n writeFileSync(\n path.join(root, \"dist\", \"__entry.js\"),\n \"const userMod = await import('./server.js');\\nexport default userMod.default;\\n\",\n );\n writeFileSync(\n path.join(root, \"dist\", \"assets\", \"view-abc.js\"),\n \"/* bundled view */\\n\",\n );\n\n await emitVercelBuildOutput(root);\n\n const outputDir = path.join(root, \".vercel\", \"output\");\n const funcDir = path.join(outputDir, \"functions\", \"mcp.func\");\n\n expect(existsSync(path.join(funcDir, \"index.js\"))).toBe(true);\n expect(\n JSON.parse(readFileSync(path.join(funcDir, \".vc-config.json\"), \"utf-8\")),\n ).toEqual(VERCEL_VC_CONFIG);\n expect(\n JSON.parse(readFileSync(path.join(funcDir, \"package.json\"), \"utf-8\")),\n ).toEqual({ type: \"module\" });\n expect(\n JSON.parse(readFileSync(path.join(outputDir, \"config.json\"), \"utf-8\")),\n ).toEqual(VERCEL_CONFIG);\n expect(\n readFileSync(\n path.join(outputDir, \"static\", \"assets\", \"view-abc.js\"),\n \"utf-8\",\n ),\n ).toContain(\"bundled view\");\n });\n});\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare function resolvePort(flagPort?: number): Promise<{
|
|
2
|
+
port: number;
|
|
3
|
+
fallback: boolean;
|
|
4
|
+
envWarning?: undefined;
|
|
5
|
+
} | {
|
|
6
|
+
port: number;
|
|
7
|
+
fallback: boolean;
|
|
8
|
+
envWarning: string;
|
|
9
|
+
}>;
|
|
10
|
+
/**
|
|
11
|
+
* Returns the first available port at or after `startPort`, incrementing
|
|
12
|
+
* by one until a free port is found or `MAX_PORT_INCREMENT` is reached.
|
|
13
|
+
*
|
|
14
|
+
* @param host - Bind address for the check. Pass `"localhost"` for
|
|
15
|
+
* services that bind to 127.0.0.1 (e.g. Vite HMR). Omit for
|
|
16
|
+
* services that bind to all interfaces (e.g. the HTTP server).
|
|
17
|
+
*/
|
|
18
|
+
export declare function detectAvailablePort(startPort: number, host?: string): Promise<number>;
|