nudge-ui 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +164 -46
- package/dist/client.mjs +252 -54
- package/dist/css/value-semantics/colorSemantics.d.ts +4 -0
- package/dist/css/value-semantics/colorSemantics.js +17 -0
- package/dist/hosts/astro/astroRuntimeConfig.js +1 -0
- package/dist/hosts/astro/clientTransport.js +41 -32
- package/dist/hosts/astro/integration.d.ts +2 -2
- package/dist/hosts/astro/integration.js +9 -4
- package/dist/hosts/astro/markdownIdentity.d.ts +28 -0
- package/dist/hosts/astro/markdownIdentity.js +81 -0
- package/dist/hosts/environment.d.ts +15 -0
- package/dist/hosts/environment.js +16 -0
- package/dist/hosts/next/manifest.js +1 -1
- package/dist/hosts/next/sidecar.js +12 -2
- package/dist/hosts/next/wrapper.d.ts +2 -0
- package/dist/hosts/next/wrapper.js +2 -1
- package/dist/hosts/projectBridge.d.ts +1 -0
- package/dist/hosts/projectBridge.js +1 -0
- package/dist/hosts/static/manifest.js +3 -1
- package/dist/hosts/static/server.js +4 -0
- package/dist/hosts/vite/vite.d.ts +4 -0
- package/dist/hosts/vite/vite.js +28 -5
- package/dist/inspector/agent/McpConnectionDialog.d.ts +3 -2
- package/dist/inspector/agent/McpConnectionDialog.js +23 -22
- package/dist/inspector/agent/activity.d.ts +18 -0
- package/dist/inspector/agent/activity.js +70 -0
- package/dist/inspector/agent/client.d.ts +8 -0
- package/dist/inspector/agent/client.js +65 -5
- package/dist/inspector/agent/connectionStatus.d.ts +3 -3
- package/dist/inspector/agent/connectionStatus.js +9 -2
- package/dist/inspector/agent/httpTransport.d.ts +6 -0
- package/dist/inspector/agent/httpTransport.js +50 -3
- package/dist/inspector/agent/protocol.d.ts +9 -3
- package/dist/inspector/agent/protocol.js +1 -1
- package/dist/inspector/agent/verification.d.ts +11 -1
- package/dist/inspector/agent/verification.js +53 -25
- package/dist/inspector/canvas/AgentActivityOverlay.d.ts +13 -0
- package/dist/inspector/canvas/AgentActivityOverlay.js +111 -0
- package/dist/inspector/canvas/CanvasCard.d.ts +9 -2
- package/dist/inspector/canvas/CanvasCard.js +133 -38
- package/dist/inspector/canvas/CanvasElementOverlay.js +200 -22
- package/dist/inspector/canvas/CanvasToolIcons.d.ts +10 -0
- package/dist/inspector/canvas/CanvasToolIcons.js +20 -0
- package/dist/inspector/canvas/CanvasToolbar.js +8 -4
- package/dist/inspector/canvas/CanvasWorkspace.js +243 -56
- package/dist/inspector/canvas/StaleChangeIndicator.js +3 -13
- package/dist/inspector/canvas/agentPresentation.d.ts +8 -8
- package/dist/inspector/canvas/agentPresentation.js +64 -52
- package/dist/inspector/canvas/canvasGestures.d.ts +1 -1
- package/dist/inspector/canvas/canvasGestures.js +1 -1
- package/dist/inspector/canvas/canvasStore.d.ts +46 -82
- package/dist/inspector/canvas/canvasStore.js +251 -284
- package/dist/inspector/canvas/frameContent.d.ts +21 -0
- package/dist/inspector/canvas/frameContent.js +44 -0
- package/dist/inspector/canvas/frameProtocol.d.ts +34 -4
- package/dist/inspector/canvas/frameProtocol.js +9 -2
- package/dist/inspector/canvas/keyboardShortcuts.d.ts +4 -1
- package/dist/inspector/canvas/keyboardShortcuts.js +5 -3
- package/dist/inspector/canvas/layout.d.ts +52 -0
- package/dist/inspector/canvas/layout.js +106 -0
- package/dist/inspector/canvas/linkEligibility.d.ts +0 -5
- package/dist/inspector/canvas/linkEligibility.js +0 -29
- package/dist/inspector/canvas/projection.d.ts +15 -5
- package/dist/inspector/canvas/projection.js +69 -13
- package/dist/inspector/canvas/rendererBootstrap.js +45 -4
- package/dist/inspector/canvas/rendererElementSelector.d.ts +1 -1
- package/dist/inspector/canvas/rendererElementSelector.js +102 -45
- package/dist/inspector/canvas/rendererStylesheet.js +2 -2
- package/dist/inspector/canvas/resizeHandleScale.js +1 -1
- package/dist/inspector/canvas/sessionStore.d.ts +11 -26
- package/dist/inspector/canvas/sessionStore.js +43 -183
- package/dist/inspector/canvas/staleChangeDetector.js +9 -3
- package/dist/inspector/canvas/useCanvasLayoutAnimation.d.ts +5 -0
- package/dist/inspector/canvas/useCanvasLayoutAnimation.js +107 -0
- package/dist/inspector/canvas/viewStore.d.ts +38 -0
- package/dist/inspector/canvas/viewStore.js +104 -0
- package/dist/inspector/canvas/wheelPan.d.ts +8 -0
- package/dist/inspector/canvas/wheelPan.js +8 -0
- package/dist/inspector/changes/changesLog.d.ts +6 -5
- package/dist/inspector/changes/changesLog.js +40 -32
- package/dist/inspector/changes/draftChanges.d.ts +56 -0
- package/dist/inspector/changes/draftChanges.js +300 -0
- package/dist/inspector/changes/previewDiagnostics.d.ts +4 -2
- package/dist/inspector/changes/previewDiagnostics.js +11 -25
- package/dist/inspector/clientManifest.d.ts +3 -1
- package/dist/inspector/clientManifest.js +1 -0
- package/dist/inspector/comments/CommentsOverlay.d.ts +2 -0
- package/dist/inspector/comments/CommentsOverlay.js +250 -0
- package/dist/inspector/comments/element.d.ts +6 -0
- package/dist/inspector/comments/element.js +47 -0
- package/dist/inspector/comments/store.d.ts +29 -0
- package/dist/inspector/comments/store.js +121 -0
- package/dist/inspector/comments/verification.d.ts +5 -0
- package/dist/inspector/comments/verification.js +52 -0
- package/dist/inspector/drafts/model.d.ts +35 -0
- package/dist/inspector/drafts/model.js +45 -0
- package/dist/inspector/drafts/store.d.ts +28 -0
- package/dist/inspector/drafts/store.js +231 -0
- package/dist/inspector/index.js +26 -35
- package/dist/inspector/inline-text/inlineTextEditor.js +7 -0
- package/dist/inspector/inspection/useBrowserCssInspection.js +15 -1
- package/dist/inspector/iterations/capture.d.ts +2 -0
- package/dist/inspector/iterations/capture.js +173 -0
- package/dist/inspector/iterations/client.d.ts +7 -0
- package/dist/inspector/iterations/client.js +52 -0
- package/dist/inspector/iterations/coordinator.d.ts +15 -0
- package/dist/inspector/iterations/coordinator.js +130 -0
- package/dist/inspector/iterations/prompt.d.ts +3 -0
- package/dist/inspector/iterations/prompt.js +26 -0
- package/dist/inspector/overlay/DomNavigator.d.ts +10 -0
- package/dist/inspector/overlay/DomNavigator.js +46 -0
- package/dist/inspector/overlay/InspectorOverlay.js +6 -2
- package/dist/inspector/overlay/clickPolicy.d.ts +18 -2
- package/dist/inspector/overlay/clickPolicy.js +34 -3
- package/dist/inspector/overlay/elementSelector.d.ts +1 -1
- package/dist/inspector/overlay/elementSelector.js +18 -7
- package/dist/inspector/overlay/interactionStyles.js +3 -1
- package/dist/inspector/overlay/spacingGestures.d.ts +15 -3
- package/dist/inspector/overlay/spacingGestures.js +88 -13
- package/dist/inspector/projection/{workspaceProjection.d.ts → draftProjection.d.ts} +6 -6
- package/dist/inspector/projection/{workspaceProjection.js → draftProjection.js} +4 -4
- package/dist/inspector/projection/renderedInstance.d.ts +2 -1
- package/dist/inspector/projection/renderedInstance.js +9 -5
- package/dist/inspector/projection/structuralProjection.d.ts +2 -1
- package/dist/inspector/projection/structuralProjection.js +19 -15
- package/dist/inspector/projection/textProjection.d.ts +2 -1
- package/dist/inspector/projection/textProjection.js +8 -4
- package/dist/inspector/prompt/PromptSettingsDialog.js +1 -5
- package/dist/inspector/prompt/clipboardHandoff.d.ts +10 -18
- package/dist/inspector/prompt/clipboardHandoff.js +92 -143
- package/dist/inspector/prompt/generatePrompt.d.ts +4 -1
- package/dist/inspector/prompt/generatePrompt.js +17 -16
- package/dist/inspector/runtime/runtimeConfig.d.ts +10 -1
- package/dist/inspector/runtime/runtimeConfig.js +24 -0
- package/dist/inspector/selection/hierarchy.d.ts +6 -0
- package/dist/inspector/selection/hierarchy.js +8 -0
- package/dist/inspector/settings/SettingsDialog.d.ts +1 -1
- package/dist/inspector/settings/SettingsDialog.js +22 -9
- package/dist/inspector/shell/AgentStatusButton.d.ts +11 -0
- package/dist/inspector/shell/AgentStatusButton.js +36 -0
- package/dist/inspector/shell/AppShell.js +4 -2
- package/dist/inspector/shell/ChangesLog.js +47 -27
- package/dist/inspector/shell/CopyPromptButton.js +146 -90
- package/dist/inspector/shell/EmptyState.js +9 -8
- package/dist/inspector/shell/InspectorShell.js +14 -25
- package/dist/inspector/shell/PeekOriginalButton.js +24 -23
- package/dist/inspector/shell/originalPreview.js +5 -5
- package/dist/inspector/shell/shortcuts.d.ts +3 -0
- package/dist/inspector/shell/shortcuts.js +11 -0
- package/dist/inspector/sketch/SketchEditor.js +14 -14
- package/dist/inspector/sketch/SketchEntryButton.js +1 -1
- package/dist/inspector/sketch/SketchFrameOverlay.d.ts +3 -1
- package/dist/inspector/sketch/SketchFrameOverlay.js +11 -8
- package/dist/inspector/sketch/SketchLayersPanel.js +13 -5
- package/dist/inspector/sketch/SketchOverlay.js +7 -7
- package/dist/inspector/sketch/SketchWorkspace.js +18 -12
- package/dist/inspector/sketch/interaction.d.ts +1 -0
- package/dist/inspector/sketch/interaction.js +8 -4
- package/dist/inspector/sketch/model.d.ts +5 -0
- package/dist/inspector/sketch/model.js +6 -2
- package/dist/inspector/sketch/raster.d.ts +1 -2
- package/dist/inspector/sketch/raster.js +68 -4
- package/dist/inspector/sketch/store.js +48 -23
- package/dist/inspector/styleEditors/BackgroundEditor.d.ts +4 -0
- package/dist/inspector/styleEditors/BackgroundEditor.js +195 -0
- package/dist/inspector/styleEditors/BorderEditor.js +49 -78
- package/dist/inspector/styleEditors/BorderRadiusEditor.js +6 -1
- package/dist/inspector/styleEditors/BoxShadowEditor.d.ts +1 -2
- package/dist/inspector/styleEditors/BoxShadowEditor.js +132 -4
- package/dist/inspector/styleEditors/ColorPicker.d.ts +5 -1
- package/dist/inspector/styleEditors/ColorPicker.js +10 -4
- package/dist/inspector/styleEditors/GapField.js +3 -5
- package/dist/inspector/styleEditors/GridChildSection.d.ts +1 -1
- package/dist/inspector/styleEditors/GridChildSection.js +18 -9
- package/dist/inspector/styleEditors/GridPicker.d.ts +1 -1
- package/dist/inspector/styleEditors/GridPicker.js +8 -2
- package/dist/inspector/styleEditors/GridSection.js +1 -1
- package/dist/inspector/styleEditors/GridValueField.js +19 -14
- package/dist/inspector/styleEditors/ImageBackgroundEditor.d.ts +18 -0
- package/dist/inspector/styleEditors/ImageBackgroundEditor.js +118 -0
- package/dist/inspector/styleEditors/LayoutBlockedIndicator.d.ts +2 -2
- package/dist/inspector/styleEditors/LayoutBlockedIndicator.js +3 -3
- package/dist/inspector/styleEditors/LayoutComboField.js +6 -4
- package/dist/inspector/styleEditors/LayoutDropdown.js +6 -3
- package/dist/inspector/styleEditors/LayoutSection.js +32 -11
- package/dist/inspector/styleEditors/SpacingBox.js +16 -9
- package/dist/inspector/styleEditors/Typography.js +11 -3
- package/dist/inspector/styleEditors/backgroundLayers.d.ts +24 -0
- package/dist/inspector/styleEditors/backgroundLayers.js +51 -0
- package/dist/inspector/styleEditors/gradientValue.d.ts +17 -0
- package/dist/inspector/styleEditors/gradientValue.js +114 -0
- package/dist/inspector/styleEditors/inlineAuthored.d.ts +10 -0
- package/dist/inspector/styleEditors/inlineAuthored.js +114 -0
- package/dist/inspector/styleEditors/layoutValue.d.ts +0 -8
- package/dist/inspector/styleEditors/layoutValue.js +0 -42
- package/dist/inspector/styleEditors/nudgeValue.d.ts +4 -4
- package/dist/inspector/styleEditors/nudgeValue.js +41 -11
- package/dist/inspector/tokens/TokenField.d.ts +7 -0
- package/dist/inspector/tokens/TokenField.js +49 -22
- package/dist/inspector/tokens/TokenLabel.js +5 -14
- package/dist/inspector/tokens/TokensPanel.js +2 -1
- package/dist/inspector/tokens/dragPointerLock.d.ts +8 -0
- package/dist/inspector/tokens/dragPointerLock.js +70 -0
- package/dist/inspector/tokens/editActions.d.ts +1 -1
- package/dist/inspector/tokens/editActions.js +1 -1
- package/dist/inspector/ui/AtRuleContext.js +4 -6
- package/dist/inspector/ui/Button.d.ts +6 -2
- package/dist/inspector/ui/Button.js +4 -3
- package/dist/inspector/ui/ControlSurface.d.ts +2 -2
- package/dist/inspector/ui/ControlSurface.js +4 -3
- package/dist/inspector/ui/Disclosure.d.ts +22 -0
- package/dist/inspector/ui/Disclosure.js +13 -0
- package/dist/inspector/ui/InlineStyleWarning.d.ts +11 -0
- package/dist/inspector/ui/InlineStyleWarning.js +13 -0
- package/dist/inspector/ui/InspectorPopover.d.ts +2 -1
- package/dist/inspector/ui/InspectorPopover.js +4 -5
- package/dist/inspector/ui/PopoverListbox.d.ts +2 -1
- package/dist/inspector/ui/PopoverListbox.js +8 -7
- package/dist/inspector/ui/SegmentedControl.d.ts +2 -1
- package/dist/inspector/ui/SegmentedControl.js +2 -2
- package/dist/inspector/ui/Select.d.ts +6 -1
- package/dist/inspector/ui/Select.js +7 -11
- package/dist/inspector/ui/SideValuesField.js +1 -1
- package/dist/inspector/ui/Tooltip.d.ts +26 -0
- package/dist/inspector/ui/Tooltip.js +32 -0
- package/dist/inspector/ui/classNames.d.ts +2 -0
- package/dist/inspector/ui/classNames.js +4 -0
- package/dist/inspector/ui/customCursors.d.ts +23 -0
- package/dist/inspector/ui/customCursors.js +122 -0
- package/dist/inspector/ui/dragCursor.d.ts +6 -0
- package/dist/inspector/ui/dragCursor.js +13 -0
- package/dist/inspector/ui/portalContainer.d.ts +2 -0
- package/dist/inspector/ui/portalContainer.js +6 -0
- package/dist/inspector/ui/styles.js +34 -24
- package/dist/inspector/workspace/commands.d.ts +9 -0
- package/dist/inspector/workspace/commands.js +82 -0
- package/dist/inspector/workspace/controller.d.ts +4 -0
- package/dist/inspector/workspace/controller.js +66 -0
- package/dist/inspector/workspace/handoff.d.ts +42 -0
- package/dist/inspector/workspace/handoff.js +115 -0
- package/dist/inspector/workspace/timeline.d.ts +30 -0
- package/dist/inspector/workspace/timeline.js +108 -0
- package/dist/internal/agent-protocol.d.ts +19 -2
- package/dist/internal/agent-protocol.js +13 -0
- package/dist/nudge-ui.mjs +560 -299
- package/dist/project/artifacts.d.ts +13 -0
- package/dist/project/artifacts.js +253 -0
- package/dist/transport/artifacts.d.ts +8 -0
- package/dist/transport/artifacts.js +9 -0
- package/dist/transport/editor.d.ts +20 -1
- package/dist/transport/editor.js +44 -11
- package/dist/transport/routes.d.ts +6 -1
- package/dist/transport/routes.js +6 -1
- package/package.json +6 -2
- package/dist/inspector/changes/workspaceChanges.d.ts +0 -43
- package/dist/inspector/changes/workspaceChanges.js +0 -239
- package/dist/inspector/shell/DomNavigation.d.ts +0 -8
- package/dist/inspector/shell/DomNavigation.js +0 -30
package/dist/nudge-ui.mjs
CHANGED
|
@@ -2020,7 +2020,7 @@ var require_util = __commonJS({
|
|
|
2020
2020
|
}
|
|
2021
2021
|
path = url.path;
|
|
2022
2022
|
}
|
|
2023
|
-
var
|
|
2023
|
+
var isAbsolute5 = exports.isAbsolute(path);
|
|
2024
2024
|
var parts = [];
|
|
2025
2025
|
var start = 0;
|
|
2026
2026
|
var i = 0;
|
|
@@ -2055,7 +2055,7 @@ var require_util = __commonJS({
|
|
|
2055
2055
|
}
|
|
2056
2056
|
path = parts.join("/");
|
|
2057
2057
|
if (path === "") {
|
|
2058
|
-
path =
|
|
2058
|
+
path = isAbsolute5 ? "/" : ".";
|
|
2059
2059
|
}
|
|
2060
2060
|
if (url) {
|
|
2061
2061
|
url.path = path;
|
|
@@ -2064,7 +2064,7 @@ var require_util = __commonJS({
|
|
|
2064
2064
|
return path;
|
|
2065
2065
|
});
|
|
2066
2066
|
exports.normalize = normalize;
|
|
2067
|
-
function
|
|
2067
|
+
function join7(aRoot, aPath) {
|
|
2068
2068
|
if (aRoot === "") {
|
|
2069
2069
|
aRoot = ".";
|
|
2070
2070
|
}
|
|
@@ -2096,11 +2096,11 @@ var require_util = __commonJS({
|
|
|
2096
2096
|
}
|
|
2097
2097
|
return joined;
|
|
2098
2098
|
}
|
|
2099
|
-
exports.join =
|
|
2099
|
+
exports.join = join7;
|
|
2100
2100
|
exports.isAbsolute = function(aPath) {
|
|
2101
2101
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
2102
2102
|
};
|
|
2103
|
-
function
|
|
2103
|
+
function relative5(aRoot, aPath) {
|
|
2104
2104
|
if (aRoot === "") {
|
|
2105
2105
|
aRoot = ".";
|
|
2106
2106
|
}
|
|
@@ -2119,7 +2119,7 @@ var require_util = __commonJS({
|
|
|
2119
2119
|
}
|
|
2120
2120
|
return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
|
|
2121
2121
|
}
|
|
2122
|
-
exports.relative =
|
|
2122
|
+
exports.relative = relative5;
|
|
2123
2123
|
var supportsNullProto = (function() {
|
|
2124
2124
|
var obj = /* @__PURE__ */ Object.create(null);
|
|
2125
2125
|
return !("__proto__" in obj);
|
|
@@ -2310,7 +2310,7 @@ var require_util = __commonJS({
|
|
|
2310
2310
|
parsed.path = parsed.path.substring(0, index + 1);
|
|
2311
2311
|
}
|
|
2312
2312
|
}
|
|
2313
|
-
sourceURL =
|
|
2313
|
+
sourceURL = join7(urlGenerate(parsed), sourceURL);
|
|
2314
2314
|
}
|
|
2315
2315
|
return normalize(sourceURL);
|
|
2316
2316
|
}
|
|
@@ -3750,8 +3750,8 @@ var require_source_map = __commonJS({
|
|
|
3750
3750
|
var require_previous_map = __commonJS({
|
|
3751
3751
|
"../../node_modules/.pnpm/postcss@8.5.26/node_modules/postcss/lib/previous-map.js"(exports, module) {
|
|
3752
3752
|
"use strict";
|
|
3753
|
-
var { existsSync: existsSync4, readFileSync, realpathSync: realpathSync3 } = __require("fs");
|
|
3754
|
-
var { dirname: dirname5, isAbsolute:
|
|
3753
|
+
var { existsSync: existsSync4, readFileSync: readFileSync2, realpathSync: realpathSync3 } = __require("fs");
|
|
3754
|
+
var { dirname: dirname5, isAbsolute: isAbsolute5, join: join7, relative: relative5, sep: sep4 } = __require("path");
|
|
3755
3755
|
var { SourceMapConsumer, SourceMapGenerator } = require_source_map();
|
|
3756
3756
|
function realPath(path) {
|
|
3757
3757
|
try {
|
|
@@ -3824,15 +3824,15 @@ var require_previous_map = __commonJS({
|
|
|
3824
3824
|
if (!trusted && !this.unsafeMap) {
|
|
3825
3825
|
if (!/\.map$/i.test(path)) return void 0;
|
|
3826
3826
|
if (!cssFile) return void 0;
|
|
3827
|
-
let rel =
|
|
3828
|
-
if (rel === ".." || rel.startsWith(".." +
|
|
3827
|
+
let rel = relative5(realPath(dirname5(cssFile)), realPath(path));
|
|
3828
|
+
if (rel === ".." || rel.startsWith(".." + sep4) || isAbsolute5(rel)) {
|
|
3829
3829
|
return void 0;
|
|
3830
3830
|
}
|
|
3831
3831
|
}
|
|
3832
3832
|
this.root = dirname5(path);
|
|
3833
3833
|
if (existsSync4(path)) {
|
|
3834
3834
|
this.mapFile = path;
|
|
3835
|
-
return
|
|
3835
|
+
return readFileSync2(path, "utf-8").toString().trim();
|
|
3836
3836
|
}
|
|
3837
3837
|
}
|
|
3838
3838
|
loadMap(file, prev) {
|
|
@@ -3866,7 +3866,7 @@ var require_previous_map = __commonJS({
|
|
|
3866
3866
|
return this.decodeInline(this.annotation);
|
|
3867
3867
|
} else if (this.annotation) {
|
|
3868
3868
|
let map = this.annotation;
|
|
3869
|
-
if (file) map =
|
|
3869
|
+
if (file) map = join7(dirname5(file), map);
|
|
3870
3870
|
let unknown = this.loadFile(map, file, false);
|
|
3871
3871
|
if (unknown) {
|
|
3872
3872
|
try {
|
|
@@ -3896,7 +3896,7 @@ var require_input = __commonJS({
|
|
|
3896
3896
|
"../../node_modules/.pnpm/postcss@8.5.26/node_modules/postcss/lib/input.js"(exports, module) {
|
|
3897
3897
|
"use strict";
|
|
3898
3898
|
var { nanoid } = require_non_secure();
|
|
3899
|
-
var { isAbsolute:
|
|
3899
|
+
var { isAbsolute: isAbsolute5, resolve: resolve5 } = __require("path");
|
|
3900
3900
|
var { SourceMapConsumer, SourceMapGenerator } = require_source_map();
|
|
3901
3901
|
var { fileURLToPath, pathToFileURL: pathToFileURL2 } = __require("url");
|
|
3902
3902
|
var CssSyntaxError2 = require_css_syntax_error();
|
|
@@ -3904,7 +3904,7 @@ var require_input = __commonJS({
|
|
|
3904
3904
|
var terminalHighlight = require_terminal_highlight();
|
|
3905
3905
|
var lineToIndexCache = /* @__PURE__ */ Symbol("lineToIndexCache");
|
|
3906
3906
|
var sourceMapAvailable = Boolean(SourceMapConsumer && SourceMapGenerator);
|
|
3907
|
-
var pathAvailable = Boolean(resolve5 &&
|
|
3907
|
+
var pathAvailable = Boolean(resolve5 && isAbsolute5);
|
|
3908
3908
|
function getLineToIndex(input) {
|
|
3909
3909
|
if (input[lineToIndexCache]) return input[lineToIndexCache];
|
|
3910
3910
|
let lines = input.css.split("\n");
|
|
@@ -3935,7 +3935,7 @@ var require_input = __commonJS({
|
|
|
3935
3935
|
this.document = this.css;
|
|
3936
3936
|
if (opts.document) this.document = opts.document.toString();
|
|
3937
3937
|
if (opts.from) {
|
|
3938
|
-
if (!pathAvailable || /^\w+:\/\//.test(opts.from) ||
|
|
3938
|
+
if (!pathAvailable || /^\w+:\/\//.test(opts.from) || isAbsolute5(opts.from)) {
|
|
3939
3939
|
this.file = opts.from;
|
|
3940
3940
|
} else {
|
|
3941
3941
|
this.file = resolve5(opts.from);
|
|
@@ -4075,7 +4075,7 @@ var require_input = __commonJS({
|
|
|
4075
4075
|
if (toPosition.source) to = toPosition;
|
|
4076
4076
|
}
|
|
4077
4077
|
let fromUrl;
|
|
4078
|
-
if (
|
|
4078
|
+
if (isAbsolute5(from.source)) {
|
|
4079
4079
|
fromUrl = pathToFileURL2(from.source);
|
|
4080
4080
|
} else {
|
|
4081
4081
|
fromUrl = new URL(
|
|
@@ -4256,8 +4256,8 @@ var require_rule = __commonJS({
|
|
|
4256
4256
|
}
|
|
4257
4257
|
set selectors(values) {
|
|
4258
4258
|
let match = this.selector ? this.selector.match(/,\s*/) : null;
|
|
4259
|
-
let
|
|
4260
|
-
this.selector = values.join(
|
|
4259
|
+
let sep4 = match ? match[0] : "," + this.raw("between", "beforeOpen");
|
|
4260
|
+
this.selector = values.join(sep4);
|
|
4261
4261
|
}
|
|
4262
4262
|
constructor(defaults) {
|
|
4263
4263
|
super(defaults);
|
|
@@ -4369,12 +4369,12 @@ var require_fromJSON = __commonJS({
|
|
|
4369
4369
|
var require_map_generator = __commonJS({
|
|
4370
4370
|
"../../node_modules/.pnpm/postcss@8.5.26/node_modules/postcss/lib/map-generator.js"(exports, module) {
|
|
4371
4371
|
"use strict";
|
|
4372
|
-
var { dirname: dirname5, relative:
|
|
4372
|
+
var { dirname: dirname5, relative: relative5, resolve: resolve5, sep: sep4 } = __require("path");
|
|
4373
4373
|
var { SourceMapConsumer, SourceMapGenerator } = require_source_map();
|
|
4374
4374
|
var { pathToFileURL: pathToFileURL2 } = __require("url");
|
|
4375
4375
|
var Input2 = require_input();
|
|
4376
4376
|
var sourceMapAvailable = Boolean(SourceMapConsumer && SourceMapGenerator);
|
|
4377
|
-
var pathAvailable = Boolean(dirname5 && resolve5 &&
|
|
4377
|
+
var pathAvailable = Boolean(dirname5 && resolve5 && relative5 && sep4);
|
|
4378
4378
|
var MapGenerator = class {
|
|
4379
4379
|
constructor(stringify2, root2, opts, cssString) {
|
|
4380
4380
|
this.stringify = stringify2;
|
|
@@ -4605,7 +4605,7 @@ var require_map_generator = __commonJS({
|
|
|
4605
4605
|
if (typeof this.mapOpts.annotation === "string") {
|
|
4606
4606
|
from = dirname5(resolve5(from, this.mapOpts.annotation));
|
|
4607
4607
|
}
|
|
4608
|
-
let path =
|
|
4608
|
+
let path = relative5(from, file);
|
|
4609
4609
|
this.memoizedPaths.set(file, path);
|
|
4610
4610
|
return path;
|
|
4611
4611
|
}
|
|
@@ -4678,7 +4678,7 @@ var require_map_generator = __commonJS({
|
|
|
4678
4678
|
toUrl(path) {
|
|
4679
4679
|
let cached = this.memoizedURLs.get(path);
|
|
4680
4680
|
if (cached) return cached;
|
|
4681
|
-
if (
|
|
4681
|
+
if (sep4 === "\\") {
|
|
4682
4682
|
path = path.replace(/\\/g, "/");
|
|
4683
4683
|
}
|
|
4684
4684
|
let url = encodeURI(path).replace(/[#?]/g, encodeURIComponent);
|
|
@@ -6182,13 +6182,13 @@ function planAgentCommand(args, projectRoot, packageVersion) {
|
|
|
6182
6182
|
throw new Error("Usage: nudge-ui agent <setup|doctor> [options]");
|
|
6183
6183
|
}
|
|
6184
6184
|
function findLocalMcp(projectRoot, projectRequire) {
|
|
6185
|
-
let
|
|
6185
|
+
let directory2 = projectRoot;
|
|
6186
6186
|
while (true) {
|
|
6187
|
-
const candidate = join(
|
|
6187
|
+
const candidate = join(directory2, "node_modules", "@nudge-ui", "mcp");
|
|
6188
6188
|
if (existsSync(join(candidate, "package.json"))) return candidate;
|
|
6189
|
-
const parent = dirname(
|
|
6190
|
-
if (parent ===
|
|
6191
|
-
|
|
6189
|
+
const parent = dirname(directory2);
|
|
6190
|
+
if (parent === directory2) break;
|
|
6191
|
+
directory2 = parent;
|
|
6192
6192
|
}
|
|
6193
6193
|
if (process.versions.pnp) {
|
|
6194
6194
|
return projectRequire.resolve("@nudge-ui/mcp");
|
|
@@ -6204,20 +6204,122 @@ function runAgentCommand(args, packageVersion) {
|
|
|
6204
6204
|
}
|
|
6205
6205
|
}
|
|
6206
6206
|
|
|
6207
|
-
// src/
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
} from "node:
|
|
6218
|
-
import {
|
|
6219
|
-
import {
|
|
6220
|
-
import {
|
|
6207
|
+
// src/transport/artifacts.ts
|
|
6208
|
+
var HTML_ARTIFACT_REVISION_ATTRIBUTE = "data-nudge-artifact-revision";
|
|
6209
|
+
var HTML_ITERATION_CONFLICT = "This iteration changed outside Nudge. Your visual edits are still pending. Create another iteration to keep your design, then clear this iteration\u2019s changes to load the external update.";
|
|
6210
|
+
function isHtmlArtifactRevision(value) {
|
|
6211
|
+
if (!value || typeof value !== "object") return false;
|
|
6212
|
+
const item = value;
|
|
6213
|
+
return typeof item.document === "string" && /^[a-f0-9]{64}$/.test(item.document) && typeof item.preview === "string" && /^[a-f0-9]{64}$/.test(item.preview);
|
|
6214
|
+
}
|
|
6215
|
+
|
|
6216
|
+
// src/project/artifacts.ts
|
|
6217
|
+
import { createHash } from "node:crypto";
|
|
6218
|
+
import { readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
6219
|
+
import { mkdir, readFile, realpath, rename, rm, writeFile } from "node:fs/promises";
|
|
6220
|
+
import { isAbsolute, join as join2, relative, sep } from "node:path";
|
|
6221
|
+
|
|
6222
|
+
// src/transport/routes.ts
|
|
6223
|
+
var NUDGE_UI_ROUTE_PREFIX = "/__nudge_ui__/";
|
|
6224
|
+
var NUDGE_UI_MANIFEST_PATH = `${NUDGE_UI_ROUTE_PREFIX}manifest`;
|
|
6225
|
+
var NUDGE_UI_CLIENT_PATH = `${NUDGE_UI_ROUTE_PREFIX}client.mjs`;
|
|
6226
|
+
var NUDGE_UI_EDITOR_PATH = `${NUDGE_UI_ROUTE_PREFIX}editor`;
|
|
6227
|
+
var NUDGE_UI_RELOAD_PATH = `${NUDGE_UI_ROUTE_PREFIX}reload`;
|
|
6228
|
+
var NUDGE_UI_ARTIFACTS_PATH = `${NUDGE_UI_ROUTE_PREFIX}artifacts`;
|
|
6229
|
+
var NUDGE_UI_MOUNT_ID = "nudge-ui-root";
|
|
6230
|
+
var NUDGE_UI_EDITOR_QUERY_PARAM = "nudge-ui";
|
|
6231
|
+
var NUDGE_UI_EDITOR_QUERY_VALUE = "editor";
|
|
6232
|
+
function isReservedNudgeUiRoute(pathname) {
|
|
6233
|
+
return pathname === NUDGE_UI_ROUTE_PREFIX.slice(0, -1) || pathname.startsWith(NUDGE_UI_ROUTE_PREFIX);
|
|
6234
|
+
}
|
|
6235
|
+
|
|
6236
|
+
// src/transport/editor.ts
|
|
6237
|
+
function isNudgeUiEditorDocumentRequest(requestHref, method, headers) {
|
|
6238
|
+
const normalizedMethod = (method ?? "GET").toUpperCase();
|
|
6239
|
+
if (normalizedMethod !== "GET" && normalizedMethod !== "HEAD") return false;
|
|
6240
|
+
const url = new URL(requestHref, "http://nudge-ui.local");
|
|
6241
|
+
if (url.pathname === NUDGE_UI_EDITOR_PATH) return true;
|
|
6242
|
+
if (!isApplicationUrl(url)) return false;
|
|
6243
|
+
if (!url.searchParams.getAll(NUDGE_UI_EDITOR_QUERY_PARAM).includes(NUDGE_UI_EDITOR_QUERY_VALUE)) return false;
|
|
6244
|
+
const header = (name) => {
|
|
6245
|
+
const value = headers?.[name] ?? headers?.[name.toLowerCase()];
|
|
6246
|
+
return typeof value === "string" ? value : value?.join(",") ?? "";
|
|
6247
|
+
};
|
|
6248
|
+
return header("sec-fetch-dest").toLowerCase() === "document" || header("accept").toLowerCase().includes("text/html");
|
|
6249
|
+
}
|
|
6250
|
+
function isApplicationUrl(url) {
|
|
6251
|
+
return (url.protocol === "http:" || url.protocol === "https:") && url.username === "" && url.password === "" && !isReservedNudgeUiRoute(url.pathname);
|
|
6252
|
+
}
|
|
6253
|
+
function createNudgeUiEditorDocument() {
|
|
6254
|
+
return `<!doctype html>
|
|
6255
|
+
<html lang="en" data-nudge-ui-editor>
|
|
6256
|
+
<head>
|
|
6257
|
+
<meta charset="utf-8">
|
|
6258
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6259
|
+
<title>Nudge UI</title>
|
|
6260
|
+
<style>html,body,#${NUDGE_UI_MOUNT_ID}{width:100%;height:100%;margin:0}body{overflow:hidden}</style>
|
|
6261
|
+
</head>
|
|
6262
|
+
<body>
|
|
6263
|
+
<div id="${NUDGE_UI_MOUNT_ID}"></div>
|
|
6264
|
+
<script type="module" src="${NUDGE_UI_CLIENT_PATH}" data-nudge-ui-client data-nudge-ui-manifest="${NUDGE_UI_MANIFEST_PATH}"></script>
|
|
6265
|
+
</body>
|
|
6266
|
+
</html>`;
|
|
6267
|
+
}
|
|
6268
|
+
|
|
6269
|
+
// src/transport/index.ts
|
|
6270
|
+
var NUDGE_UI_MANIFEST_VERSION = 1;
|
|
6271
|
+
|
|
6272
|
+
// src/hosts/environment.ts
|
|
6273
|
+
function readNudgeUiEnvironmentSwitch(env = process.env) {
|
|
6274
|
+
const value = env.NUDGE_UI?.trim().toLowerCase();
|
|
6275
|
+
if (value === "0" || value === "false" || value === "off") return "off";
|
|
6276
|
+
if (value === "1" || value === "true" || value === "on") return "on";
|
|
6277
|
+
return null;
|
|
6278
|
+
}
|
|
6279
|
+
function automationManifestFields(env = process.env) {
|
|
6280
|
+
return readNudgeUiEnvironmentSwitch(env) === "on" ? { inspectAutomatedBrowsers: true } : {};
|
|
6281
|
+
}
|
|
6282
|
+
|
|
6283
|
+
// src/hosts/static/manifest.ts
|
|
6284
|
+
function createStandaloneRuntimeManifest(projectId, tokenSnapshot = emptyTokenSnapshot(), revision2 = 0) {
|
|
6285
|
+
return {
|
|
6286
|
+
version: NUDGE_UI_MANIFEST_VERSION,
|
|
6287
|
+
revision: revision2,
|
|
6288
|
+
runtime: {
|
|
6289
|
+
projectId,
|
|
6290
|
+
host: "static-html",
|
|
6291
|
+
framework: "HTML",
|
|
6292
|
+
stylingSystem: "CSS custom properties",
|
|
6293
|
+
// Canvas shares the Vite host's controller/renderer runtime (ADR-0012):
|
|
6294
|
+
// every served document carries the bootstrap, so card iframes boot as
|
|
6295
|
+
// renderers without host-specific code.
|
|
6296
|
+
capabilities: { canvas: true, componentSemantics: false, domNavigation: true },
|
|
6297
|
+
tokenCatalog: tokenSnapshot.tokenCatalog,
|
|
6298
|
+
tokens: tokenSnapshot.tokens,
|
|
6299
|
+
tokenDiagnostics: tokenSnapshot.tokenDiagnostics,
|
|
6300
|
+
tokenGeneration: tokenSnapshot.tokenGeneration,
|
|
6301
|
+
componentContracts: []
|
|
6302
|
+
},
|
|
6303
|
+
document: {
|
|
6304
|
+
runtimeIdentity: "static-html",
|
|
6305
|
+
stylesheetOrder: "browser"
|
|
6306
|
+
},
|
|
6307
|
+
reload: {
|
|
6308
|
+
endpoint: NUDGE_UI_RELOAD_PATH,
|
|
6309
|
+
strategy: "reload-document",
|
|
6310
|
+
events: ["ready", "reload"]
|
|
6311
|
+
},
|
|
6312
|
+
...automationManifestFields()
|
|
6313
|
+
};
|
|
6314
|
+
}
|
|
6315
|
+
function emptyTokenSnapshot() {
|
|
6316
|
+
return {
|
|
6317
|
+
tokenCatalog: [],
|
|
6318
|
+
tokens: [],
|
|
6319
|
+
tokenDiagnostics: [],
|
|
6320
|
+
tokenGeneration: "empty"
|
|
6321
|
+
};
|
|
6322
|
+
}
|
|
6221
6323
|
|
|
6222
6324
|
// ../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/common/unicode.js
|
|
6223
6325
|
var UNDEFINED_CODE_POINTS = /* @__PURE__ */ new Set([
|
|
@@ -14073,6 +14175,323 @@ function parse(html, options) {
|
|
|
14073
14175
|
return Parser.parse(html, options);
|
|
14074
14176
|
}
|
|
14075
14177
|
|
|
14178
|
+
// src/hosts/static/html/bootstrap.ts
|
|
14179
|
+
var CLIENT_MARKER = "data-nudge-ui-client";
|
|
14180
|
+
var MOUNT_MARKER = "data-nudge-ui-mount";
|
|
14181
|
+
function injectStandaloneBootstrap(html, options = {}) {
|
|
14182
|
+
const clientPath = options.clientPath ?? NUDGE_UI_CLIENT_PATH;
|
|
14183
|
+
const manifestPath = options.manifestPath ?? NUDGE_UI_MANIFEST_PATH;
|
|
14184
|
+
const document2 = parse(html, { sourceCodeLocationInfo: true });
|
|
14185
|
+
const sourceFacts = inspectSource(document2, clientPath);
|
|
14186
|
+
const nodes = [];
|
|
14187
|
+
if (!sourceFacts.hasMount) {
|
|
14188
|
+
nodes.push(
|
|
14189
|
+
`<div id="${NUDGE_UI_MOUNT_ID}" ${MOUNT_MARKER}></div>`
|
|
14190
|
+
);
|
|
14191
|
+
}
|
|
14192
|
+
if (!sourceFacts.hasClient) {
|
|
14193
|
+
nodes.push(
|
|
14194
|
+
`<script type="module" src="${escapeAttributeValue(clientPath)}" ${CLIENT_MARKER} data-nudge-ui-manifest="${escapeAttributeValue(manifestPath)}"></script>`
|
|
14195
|
+
);
|
|
14196
|
+
}
|
|
14197
|
+
if (nodes.length === 0) return { html, injected: false };
|
|
14198
|
+
const injection = `
|
|
14199
|
+
${nodes.join("\n")}
|
|
14200
|
+
`;
|
|
14201
|
+
const offset = sourceFacts.bodyEndOffset ?? sourceFacts.htmlEndOffset ?? html.length;
|
|
14202
|
+
return {
|
|
14203
|
+
html: `${html.slice(0, offset)}${injection}${html.slice(offset)}`,
|
|
14204
|
+
injected: true
|
|
14205
|
+
};
|
|
14206
|
+
}
|
|
14207
|
+
function inspectSource(document2, clientPath) {
|
|
14208
|
+
const facts = {
|
|
14209
|
+
hasMount: false,
|
|
14210
|
+
hasClient: false,
|
|
14211
|
+
bodyEndOffset: null,
|
|
14212
|
+
htmlEndOffset: null
|
|
14213
|
+
};
|
|
14214
|
+
let body2 = null;
|
|
14215
|
+
visitElements(document2, (element) => {
|
|
14216
|
+
if (element.namespaceURI !== "http://www.w3.org/1999/xhtml") return;
|
|
14217
|
+
const tagName = element.tagName.toLowerCase();
|
|
14218
|
+
if (tagName === "body") body2 = element;
|
|
14219
|
+
if (tagName === "script" && (attributeValue(element, CLIENT_MARKER) !== null || attributeValue(element, "src") === clientPath)) {
|
|
14220
|
+
facts.hasClient = true;
|
|
14221
|
+
}
|
|
14222
|
+
const endOffset = element.sourceCodeLocation?.endTag?.startOffset;
|
|
14223
|
+
if (tagName === "body" && endOffset !== void 0) facts.bodyEndOffset = endOffset;
|
|
14224
|
+
if (tagName === "html" && endOffset !== void 0) facts.htmlEndOffset = endOffset;
|
|
14225
|
+
});
|
|
14226
|
+
if (body2) {
|
|
14227
|
+
visitElements(body2, (element) => {
|
|
14228
|
+
if (element !== body2 && attributeValue(element, "id") === NUDGE_UI_MOUNT_ID) {
|
|
14229
|
+
facts.hasMount = true;
|
|
14230
|
+
}
|
|
14231
|
+
});
|
|
14232
|
+
}
|
|
14233
|
+
return facts;
|
|
14234
|
+
}
|
|
14235
|
+
function visitElements(parent, visit) {
|
|
14236
|
+
for (const child of parent.childNodes) {
|
|
14237
|
+
if (!("tagName" in child) || typeof child.tagName !== "string") continue;
|
|
14238
|
+
if (child.tagName.toLowerCase() === "template") continue;
|
|
14239
|
+
visit(child);
|
|
14240
|
+
visitElements(child, visit);
|
|
14241
|
+
}
|
|
14242
|
+
}
|
|
14243
|
+
function attributeValue(element, name) {
|
|
14244
|
+
return element.attrs.find((attribute) => attribute.name === name)?.value ?? null;
|
|
14245
|
+
}
|
|
14246
|
+
function escapeAttributeValue(value) {
|
|
14247
|
+
return value.replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<").replaceAll(">", ">");
|
|
14248
|
+
}
|
|
14249
|
+
|
|
14250
|
+
// src/project/artifacts.ts
|
|
14251
|
+
var artifactOperations = /* @__PURE__ */ new Map();
|
|
14252
|
+
async function withArtifactLock(path, operation) {
|
|
14253
|
+
const previous = artifactOperations.get(path) ?? Promise.resolve();
|
|
14254
|
+
const pending = previous.catch(() => void 0).then(operation);
|
|
14255
|
+
artifactOperations.set(path, pending);
|
|
14256
|
+
try {
|
|
14257
|
+
return await pending;
|
|
14258
|
+
} finally {
|
|
14259
|
+
if (artifactOperations.get(path) === pending) artifactOperations.delete(path);
|
|
14260
|
+
}
|
|
14261
|
+
}
|
|
14262
|
+
function revision(html) {
|
|
14263
|
+
return createHash("sha256").update(html).digest("hex");
|
|
14264
|
+
}
|
|
14265
|
+
async function readRevision(target) {
|
|
14266
|
+
const [document2, preview] = await Promise.all([
|
|
14267
|
+
readFile(join2(target, "document.html")),
|
|
14268
|
+
readFile(join2(target, "preview.html"))
|
|
14269
|
+
]);
|
|
14270
|
+
return { document: revision(document2), preview: revision(preview) };
|
|
14271
|
+
}
|
|
14272
|
+
function sameRevision(left, right) {
|
|
14273
|
+
return left.document === right.document && left.preview === right.preview;
|
|
14274
|
+
}
|
|
14275
|
+
var ID = /^[a-f0-9-]{36}$/i;
|
|
14276
|
+
var MAX_BYTES = 12 * 1024 * 1024;
|
|
14277
|
+
var INERT_INTERACTIONS = `<script data-nudge-artifact-guard>
|
|
14278
|
+
document.addEventListener("submit", event => event.preventDefault(), true);
|
|
14279
|
+
document.addEventListener("click", event => {
|
|
14280
|
+
if (event.target instanceof Element && event.target.closest("a")) event.preventDefault();
|
|
14281
|
+
}, true);
|
|
14282
|
+
</script>`;
|
|
14283
|
+
async function directory(root2, id) {
|
|
14284
|
+
const project = await realpath(root2);
|
|
14285
|
+
const artifacts = join2(project, ".nudge", "artifacts");
|
|
14286
|
+
await mkdir(artifacts, { recursive: true });
|
|
14287
|
+
const actual = await realpath(artifacts);
|
|
14288
|
+
const pathFromRoot = relative(project, actual);
|
|
14289
|
+
if (pathFromRoot === ".." || pathFromRoot.startsWith(`..${sep}`) || isAbsolute(pathFromRoot)) {
|
|
14290
|
+
throw new Error("Artifact storage must remain inside the project root");
|
|
14291
|
+
}
|
|
14292
|
+
return join2(actual, id);
|
|
14293
|
+
}
|
|
14294
|
+
async function body(request) {
|
|
14295
|
+
const chunks = [];
|
|
14296
|
+
let size = 0;
|
|
14297
|
+
for await (const chunk of request) {
|
|
14298
|
+
const data = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
14299
|
+
size += data.byteLength;
|
|
14300
|
+
if (size > MAX_BYTES) throw new Error("HTML artifact exceeds 12 MB");
|
|
14301
|
+
chunks.push(data);
|
|
14302
|
+
}
|
|
14303
|
+
const text = Buffer.concat(chunks).toString("utf8");
|
|
14304
|
+
return text.length === 0 ? {} : JSON.parse(text);
|
|
14305
|
+
}
|
|
14306
|
+
function respond(response, status, content, type = "text/plain; charset=utf-8") {
|
|
14307
|
+
response.writeHead(status, {
|
|
14308
|
+
"content-type": type,
|
|
14309
|
+
"cache-control": "no-store",
|
|
14310
|
+
"x-content-type-options": "nosniff"
|
|
14311
|
+
});
|
|
14312
|
+
response.end(content);
|
|
14313
|
+
}
|
|
14314
|
+
async function handleHtmlArtifactRequest(request, response, root2, transformHtml) {
|
|
14315
|
+
const pathname = new URL(request.url ?? "/", "http://nudge-ui.local").pathname;
|
|
14316
|
+
if (pathname !== NUDGE_UI_ARTIFACTS_PATH && !pathname.startsWith(`${NUDGE_UI_ARTIFACTS_PATH}/`)) return false;
|
|
14317
|
+
const parts = pathname.slice(NUDGE_UI_ARTIFACTS_PATH.length).split("/").filter(Boolean);
|
|
14318
|
+
if (request.method !== "GET" && request.method !== "HEAD") {
|
|
14319
|
+
const origin = request.headers.origin;
|
|
14320
|
+
const host = request.headers.host;
|
|
14321
|
+
if (origin && host) {
|
|
14322
|
+
try {
|
|
14323
|
+
if (new URL(origin).host !== host) {
|
|
14324
|
+
respond(response, 403, "Cross-origin artifact writes are not allowed");
|
|
14325
|
+
return true;
|
|
14326
|
+
}
|
|
14327
|
+
} catch {
|
|
14328
|
+
respond(response, 403, "Invalid request origin");
|
|
14329
|
+
return true;
|
|
14330
|
+
}
|
|
14331
|
+
}
|
|
14332
|
+
}
|
|
14333
|
+
const id = parts[0];
|
|
14334
|
+
if (parts.length > 2 || id && !ID.test(id) || parts.length === 2 && !["document", "baseline", "preview", "commit", "revision"].includes(parts[1])) {
|
|
14335
|
+
respond(response, 404, "Not Found");
|
|
14336
|
+
return true;
|
|
14337
|
+
}
|
|
14338
|
+
try {
|
|
14339
|
+
if (request.method === "POST" && parts.length === 0) {
|
|
14340
|
+
const input = await body(request);
|
|
14341
|
+
if (!validArtifact(input)) {
|
|
14342
|
+
respond(response, 400, "Invalid artifact");
|
|
14343
|
+
return true;
|
|
14344
|
+
}
|
|
14345
|
+
const target2 = await directory(root2, input.id);
|
|
14346
|
+
const temporary = `${target2}.create-${crypto.randomUUID()}`;
|
|
14347
|
+
const metadata = {
|
|
14348
|
+
id: input.id,
|
|
14349
|
+
sourceUrl: input.sourceUrl,
|
|
14350
|
+
title: input.title,
|
|
14351
|
+
capturedAt: Date.now(),
|
|
14352
|
+
viewport: input.viewport
|
|
14353
|
+
};
|
|
14354
|
+
await mkdir(temporary);
|
|
14355
|
+
try {
|
|
14356
|
+
await writeFile(join2(temporary, "baseline.html"), input.html);
|
|
14357
|
+
await writeFile(join2(temporary, "preview.html"), input.html);
|
|
14358
|
+
await writeFile(join2(temporary, "document.html"), input.html);
|
|
14359
|
+
await writeFile(join2(temporary, "metadata.json"), JSON.stringify(metadata));
|
|
14360
|
+
await rename(temporary, target2);
|
|
14361
|
+
} catch (error) {
|
|
14362
|
+
await rm(temporary, { recursive: true, force: true });
|
|
14363
|
+
throw error;
|
|
14364
|
+
}
|
|
14365
|
+
respond(response, 201, JSON.stringify(metadata), "application/json; charset=utf-8");
|
|
14366
|
+
return true;
|
|
14367
|
+
}
|
|
14368
|
+
if (!id) {
|
|
14369
|
+
respond(response, 405, "Method Not Allowed");
|
|
14370
|
+
return true;
|
|
14371
|
+
}
|
|
14372
|
+
const target = await directory(root2, id);
|
|
14373
|
+
return await withArtifactLock(target, async () => {
|
|
14374
|
+
if (request.method !== "DELETE") {
|
|
14375
|
+
const actual = await realpath(target);
|
|
14376
|
+
if (actual !== target) throw new Error("Artifact directory must not be a symbolic link");
|
|
14377
|
+
}
|
|
14378
|
+
if (request.method === "GET" && parts[1] === "revision") {
|
|
14379
|
+
respond(response, 200, JSON.stringify(await readRevision(target)), "application/json; charset=utf-8");
|
|
14380
|
+
return true;
|
|
14381
|
+
}
|
|
14382
|
+
if (request.method === "GET" && parts.length === 2 && parts[1] !== "commit") {
|
|
14383
|
+
const file = parts[1] === "baseline" ? "baseline.html" : parts[1] === "preview" ? "preview.html" : "document.html";
|
|
14384
|
+
const html = await readFile(join2(target, file), "utf8");
|
|
14385
|
+
const stamped = html.replace(/<html\b/i, `<html ${HTML_ARTIFACT_REVISION_ATTRIBUTE}="${revision(html)}"`);
|
|
14386
|
+
const bootstrapped = injectStandaloneBootstrap(stamped).html;
|
|
14387
|
+
const guarded = bootstrapped.replace(/<\/body>/i, `${INERT_INTERACTIONS}</body>`);
|
|
14388
|
+
respond(response, 200, transformHtml ? await transformHtml(guarded) : guarded, "text/html; charset=utf-8");
|
|
14389
|
+
return true;
|
|
14390
|
+
}
|
|
14391
|
+
if (request.method === "GET" && parts.length === 1) {
|
|
14392
|
+
respond(response, 200, await readFile(join2(target, "metadata.json"), "utf8"), "application/json; charset=utf-8");
|
|
14393
|
+
return true;
|
|
14394
|
+
}
|
|
14395
|
+
if (request.method === "PUT" && parts[1] === "document" || request.method === "POST" && parts[1] === "commit") {
|
|
14396
|
+
const input = await body(request);
|
|
14397
|
+
if (!input || typeof input !== "object") {
|
|
14398
|
+
respond(response, 400, "Invalid document");
|
|
14399
|
+
return true;
|
|
14400
|
+
}
|
|
14401
|
+
const item = input;
|
|
14402
|
+
if (!isHtmlArtifactRevision(item.expected)) {
|
|
14403
|
+
respond(response, 428, "An expected iteration revision is required");
|
|
14404
|
+
return true;
|
|
14405
|
+
}
|
|
14406
|
+
if (item.html !== void 0 && typeof item.html !== "string" || request.method === "PUT" && typeof item.html !== "string") {
|
|
14407
|
+
respond(response, 400, "Invalid document");
|
|
14408
|
+
return true;
|
|
14409
|
+
}
|
|
14410
|
+
const expected = item.expected;
|
|
14411
|
+
if (!sameRevision(await readRevision(target), expected)) {
|
|
14412
|
+
respond(response, 409, HTML_ITERATION_CONFLICT);
|
|
14413
|
+
return true;
|
|
14414
|
+
}
|
|
14415
|
+
const html = typeof item.html === "string" ? item.html : await readFile(join2(target, "document.html"), "utf8");
|
|
14416
|
+
const writes = request.method === "POST" ? ["preview.html"] : [];
|
|
14417
|
+
if (typeof item.html === "string") writes.push("document.html");
|
|
14418
|
+
const previewBefore = await readFile(join2(target, "preview.html"));
|
|
14419
|
+
const temporaryFiles = [];
|
|
14420
|
+
try {
|
|
14421
|
+
for (const file of writes) {
|
|
14422
|
+
const temporary = join2(target, `${file}-${crypto.randomUUID()}.tmp`);
|
|
14423
|
+
temporaryFiles.push({ temporary, destination: join2(target, file) });
|
|
14424
|
+
await writeFile(temporary, html);
|
|
14425
|
+
}
|
|
14426
|
+
const latest = {
|
|
14427
|
+
document: revision(readFileSync(join2(target, "document.html"))),
|
|
14428
|
+
preview: revision(readFileSync(join2(target, "preview.html")))
|
|
14429
|
+
};
|
|
14430
|
+
if (!sameRevision(latest, expected)) {
|
|
14431
|
+
respond(response, 409, HTML_ITERATION_CONFLICT);
|
|
14432
|
+
return true;
|
|
14433
|
+
}
|
|
14434
|
+
let replacedPreview = false;
|
|
14435
|
+
try {
|
|
14436
|
+
for (const file of temporaryFiles) {
|
|
14437
|
+
renameSync(file.temporary, file.destination);
|
|
14438
|
+
replacedPreview ||= file.destination === join2(target, "preview.html");
|
|
14439
|
+
}
|
|
14440
|
+
} catch (error) {
|
|
14441
|
+
if (replacedPreview) {
|
|
14442
|
+
const rollback = join2(target, `preview-rollback-${crypto.randomUUID()}.tmp`);
|
|
14443
|
+
writeFileSync(rollback, previewBefore);
|
|
14444
|
+
renameSync(rollback, join2(target, "preview.html"));
|
|
14445
|
+
}
|
|
14446
|
+
throw error;
|
|
14447
|
+
}
|
|
14448
|
+
} finally {
|
|
14449
|
+
await Promise.all(temporaryFiles.map((file) => rm(file.temporary, { force: true }).catch(() => void 0)));
|
|
14450
|
+
}
|
|
14451
|
+
const saved = revision(html);
|
|
14452
|
+
respond(response, 200, JSON.stringify({ document: saved, preview: request.method === "POST" ? saved : expected.preview }), "application/json; charset=utf-8");
|
|
14453
|
+
return true;
|
|
14454
|
+
}
|
|
14455
|
+
if (request.method === "DELETE" && parts.length === 1) {
|
|
14456
|
+
await rm(target, { recursive: true, force: true });
|
|
14457
|
+
respond(response, 204, "");
|
|
14458
|
+
return true;
|
|
14459
|
+
}
|
|
14460
|
+
respond(response, 405, "Method Not Allowed");
|
|
14461
|
+
return true;
|
|
14462
|
+
});
|
|
14463
|
+
} catch (error) {
|
|
14464
|
+
const code = error.code;
|
|
14465
|
+
respond(
|
|
14466
|
+
response,
|
|
14467
|
+
code === "ENOENT" ? 404 : code === "EEXIST" || code === "ENOTEMPTY" ? 409 : 500,
|
|
14468
|
+
code === "ENOENT" ? "Artifact not found" : error instanceof Error ? error.message : "Artifact storage failed"
|
|
14469
|
+
);
|
|
14470
|
+
}
|
|
14471
|
+
return true;
|
|
14472
|
+
}
|
|
14473
|
+
function validArtifact(value) {
|
|
14474
|
+
if (!value || typeof value !== "object") return false;
|
|
14475
|
+
const item = value;
|
|
14476
|
+
const viewport = item.viewport;
|
|
14477
|
+
return typeof item.id === "string" && ID.test(item.id) && typeof item.sourceUrl === "string" && item.sourceUrl.length < 4096 && typeof item.title === "string" && item.title.length < 512 && typeof item.html === "string" && item.html.length > 0 && !!viewport && typeof viewport.width === "number" && typeof viewport.height === "number";
|
|
14478
|
+
}
|
|
14479
|
+
|
|
14480
|
+
// src/hosts/static/server.ts
|
|
14481
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
14482
|
+
import {
|
|
14483
|
+
createServer
|
|
14484
|
+
} from "node:http";
|
|
14485
|
+
import {
|
|
14486
|
+
constants,
|
|
14487
|
+
existsSync as existsSync3,
|
|
14488
|
+
realpathSync as realpathSync2,
|
|
14489
|
+
statSync as statSync2
|
|
14490
|
+
} from "node:fs";
|
|
14491
|
+
import { open, stat as stat2 } from "node:fs/promises";
|
|
14492
|
+
import { dirname as dirname4, extname as extname2, isAbsolute as isAbsolute4, join as join6, relative as relative4, resolve as resolve3 } from "node:path";
|
|
14493
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
14494
|
+
|
|
14076
14495
|
// src/html/dom.ts
|
|
14077
14496
|
var HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
|
|
14078
14497
|
var EXCLUDED_TAG_NAMES = /* @__PURE__ */ new Set([
|
|
@@ -14106,7 +14525,7 @@ function findBodyElements(document2) {
|
|
|
14106
14525
|
visit(document2);
|
|
14107
14526
|
return bodies;
|
|
14108
14527
|
}
|
|
14109
|
-
function
|
|
14528
|
+
function escapeAttributeValue2(value) {
|
|
14110
14529
|
return value.replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<").replaceAll(">", ">");
|
|
14111
14530
|
}
|
|
14112
14531
|
|
|
@@ -14160,19 +14579,6 @@ function positionAt(positions, offset) {
|
|
|
14160
14579
|
return { line: low + 1, column: offset - lineStarts[low] + 1 };
|
|
14161
14580
|
}
|
|
14162
14581
|
|
|
14163
|
-
// src/transport/routes.ts
|
|
14164
|
-
var NUDGE_UI_ROUTE_PREFIX = "/__nudge_ui__/";
|
|
14165
|
-
var NUDGE_UI_MANIFEST_PATH = `${NUDGE_UI_ROUTE_PREFIX}manifest`;
|
|
14166
|
-
var NUDGE_UI_CLIENT_PATH = `${NUDGE_UI_ROUTE_PREFIX}client.mjs`;
|
|
14167
|
-
var NUDGE_UI_EDITOR_PATH = `${NUDGE_UI_ROUTE_PREFIX}editor`;
|
|
14168
|
-
var NUDGE_UI_RELOAD_PATH = `${NUDGE_UI_ROUTE_PREFIX}reload`;
|
|
14169
|
-
var NUDGE_UI_MOUNT_ID = "nudge-ui-root";
|
|
14170
|
-
var NUDGE_UI_EDITOR_QUERY_PARAM = "nudge-ui";
|
|
14171
|
-
var NUDGE_UI_EDITOR_QUERY_VALUE = "editor";
|
|
14172
|
-
function isReservedNudgeUiRoute(pathname) {
|
|
14173
|
-
return pathname === NUDGE_UI_ROUTE_PREFIX.slice(0, -1) || pathname.startsWith(NUDGE_UI_ROUTE_PREFIX);
|
|
14174
|
-
}
|
|
14175
|
-
|
|
14176
14582
|
// src/html/identity.ts
|
|
14177
14583
|
function runIdentityPass(source, pass) {
|
|
14178
14584
|
const diagnostics = [];
|
|
@@ -14245,8 +14651,8 @@ function runIdentityPass(source, pass) {
|
|
|
14245
14651
|
if (isElement(child)) visit(child);
|
|
14246
14652
|
}
|
|
14247
14653
|
};
|
|
14248
|
-
for (const
|
|
14249
|
-
for (const child of
|
|
14654
|
+
for (const body2 of findBodyElements(document2)) {
|
|
14655
|
+
for (const child of body2.childNodes) {
|
|
14250
14656
|
if (isElement(child)) visit(child);
|
|
14251
14657
|
}
|
|
14252
14658
|
}
|
|
@@ -14262,168 +14668,20 @@ function instrumentSourceHtml(source, file) {
|
|
|
14262
14668
|
attributesFor({ element, line, column }) {
|
|
14263
14669
|
const attributes = [];
|
|
14264
14670
|
if (!hasAttribute(element, "data-cid")) {
|
|
14265
|
-
attributes.push(`data-cid="${
|
|
14671
|
+
attributes.push(`data-cid="${escapeAttributeValue2(`html:${element.tagName}`)}"`);
|
|
14266
14672
|
}
|
|
14267
14673
|
if (!hasAttribute(element, "data-src")) {
|
|
14268
|
-
attributes.push(`data-src="${
|
|
14674
|
+
attributes.push(`data-src="${escapeAttributeValue2(`${file}:${line}:${column}`)}"`);
|
|
14269
14675
|
}
|
|
14270
14676
|
return attributes;
|
|
14271
14677
|
}
|
|
14272
14678
|
});
|
|
14273
14679
|
}
|
|
14274
14680
|
|
|
14275
|
-
// src/transport/editor.ts
|
|
14276
|
-
function isNudgeUiEditorDocumentRequest(requestHref, method, headers) {
|
|
14277
|
-
const normalizedMethod = (method ?? "GET").toUpperCase();
|
|
14278
|
-
if (normalizedMethod !== "GET" && normalizedMethod !== "HEAD") return false;
|
|
14279
|
-
const url = new URL(requestHref, "http://nudge-ui.local");
|
|
14280
|
-
if (url.pathname === NUDGE_UI_EDITOR_PATH) return true;
|
|
14281
|
-
if (!isApplicationUrl(url)) return false;
|
|
14282
|
-
if (!url.searchParams.getAll(NUDGE_UI_EDITOR_QUERY_PARAM).includes(NUDGE_UI_EDITOR_QUERY_VALUE)) return false;
|
|
14283
|
-
const header = (name) => {
|
|
14284
|
-
const value = headers?.[name] ?? headers?.[name.toLowerCase()];
|
|
14285
|
-
return typeof value === "string" ? value : value?.join(",") ?? "";
|
|
14286
|
-
};
|
|
14287
|
-
return header("sec-fetch-dest").toLowerCase() === "document" || header("accept").toLowerCase().includes("text/html");
|
|
14288
|
-
}
|
|
14289
|
-
function isApplicationUrl(url) {
|
|
14290
|
-
return (url.protocol === "http:" || url.protocol === "https:") && url.username === "" && url.password === "" && !isReservedNudgeUiRoute(url.pathname);
|
|
14291
|
-
}
|
|
14292
|
-
function createNudgeUiEditorDocument() {
|
|
14293
|
-
return `<!doctype html>
|
|
14294
|
-
<html lang="en" data-nudge-ui-editor>
|
|
14295
|
-
<head>
|
|
14296
|
-
<meta charset="utf-8">
|
|
14297
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
14298
|
-
<title>Nudge UI</title>
|
|
14299
|
-
<style>html,body,#${NUDGE_UI_MOUNT_ID}{width:100%;height:100%;margin:0}body{overflow:hidden}</style>
|
|
14300
|
-
</head>
|
|
14301
|
-
<body>
|
|
14302
|
-
<div id="${NUDGE_UI_MOUNT_ID}"></div>
|
|
14303
|
-
<script type="module" src="${NUDGE_UI_CLIENT_PATH}" data-nudge-ui-client data-nudge-ui-manifest="${NUDGE_UI_MANIFEST_PATH}"></script>
|
|
14304
|
-
</body>
|
|
14305
|
-
</html>`;
|
|
14306
|
-
}
|
|
14307
|
-
|
|
14308
|
-
// src/transport/index.ts
|
|
14309
|
-
var NUDGE_UI_MANIFEST_VERSION = 1;
|
|
14310
|
-
|
|
14311
|
-
// src/hosts/static/manifest.ts
|
|
14312
|
-
function createStandaloneRuntimeManifest(projectId, tokenSnapshot = emptyTokenSnapshot(), revision = 0) {
|
|
14313
|
-
return {
|
|
14314
|
-
version: NUDGE_UI_MANIFEST_VERSION,
|
|
14315
|
-
revision,
|
|
14316
|
-
runtime: {
|
|
14317
|
-
projectId,
|
|
14318
|
-
host: "static-html",
|
|
14319
|
-
framework: "HTML",
|
|
14320
|
-
stylingSystem: "CSS custom properties",
|
|
14321
|
-
// Canvas shares the Vite host's controller/renderer runtime (ADR-0012):
|
|
14322
|
-
// every served document carries the bootstrap, so card iframes boot as
|
|
14323
|
-
// renderers without host-specific code.
|
|
14324
|
-
capabilities: { canvas: true, componentSemantics: false },
|
|
14325
|
-
tokenCatalog: tokenSnapshot.tokenCatalog,
|
|
14326
|
-
tokens: tokenSnapshot.tokens,
|
|
14327
|
-
tokenDiagnostics: tokenSnapshot.tokenDiagnostics,
|
|
14328
|
-
tokenGeneration: tokenSnapshot.tokenGeneration,
|
|
14329
|
-
componentContracts: []
|
|
14330
|
-
},
|
|
14331
|
-
document: {
|
|
14332
|
-
runtimeIdentity: "static-html",
|
|
14333
|
-
stylesheetOrder: "browser"
|
|
14334
|
-
},
|
|
14335
|
-
reload: {
|
|
14336
|
-
endpoint: NUDGE_UI_RELOAD_PATH,
|
|
14337
|
-
strategy: "reload-document",
|
|
14338
|
-
events: ["ready", "reload"]
|
|
14339
|
-
}
|
|
14340
|
-
};
|
|
14341
|
-
}
|
|
14342
|
-
function emptyTokenSnapshot() {
|
|
14343
|
-
return {
|
|
14344
|
-
tokenCatalog: [],
|
|
14345
|
-
tokens: [],
|
|
14346
|
-
tokenDiagnostics: [],
|
|
14347
|
-
tokenGeneration: "empty"
|
|
14348
|
-
};
|
|
14349
|
-
}
|
|
14350
|
-
|
|
14351
|
-
// src/hosts/static/html/bootstrap.ts
|
|
14352
|
-
var CLIENT_MARKER = "data-nudge-ui-client";
|
|
14353
|
-
var MOUNT_MARKER = "data-nudge-ui-mount";
|
|
14354
|
-
function injectStandaloneBootstrap(html, options = {}) {
|
|
14355
|
-
const clientPath = options.clientPath ?? NUDGE_UI_CLIENT_PATH;
|
|
14356
|
-
const manifestPath = options.manifestPath ?? NUDGE_UI_MANIFEST_PATH;
|
|
14357
|
-
const document2 = parse(html, { sourceCodeLocationInfo: true });
|
|
14358
|
-
const sourceFacts = inspectSource(document2, clientPath);
|
|
14359
|
-
const nodes = [];
|
|
14360
|
-
if (!sourceFacts.hasMount) {
|
|
14361
|
-
nodes.push(
|
|
14362
|
-
`<div id="${NUDGE_UI_MOUNT_ID}" ${MOUNT_MARKER}></div>`
|
|
14363
|
-
);
|
|
14364
|
-
}
|
|
14365
|
-
if (!sourceFacts.hasClient) {
|
|
14366
|
-
nodes.push(
|
|
14367
|
-
`<script type="module" src="${escapeAttributeValue2(clientPath)}" ${CLIENT_MARKER} data-nudge-ui-manifest="${escapeAttributeValue2(manifestPath)}"></script>`
|
|
14368
|
-
);
|
|
14369
|
-
}
|
|
14370
|
-
if (nodes.length === 0) return { html, injected: false };
|
|
14371
|
-
const injection = `
|
|
14372
|
-
${nodes.join("\n")}
|
|
14373
|
-
`;
|
|
14374
|
-
const offset = sourceFacts.bodyEndOffset ?? sourceFacts.htmlEndOffset ?? html.length;
|
|
14375
|
-
return {
|
|
14376
|
-
html: `${html.slice(0, offset)}${injection}${html.slice(offset)}`,
|
|
14377
|
-
injected: true
|
|
14378
|
-
};
|
|
14379
|
-
}
|
|
14380
|
-
function inspectSource(document2, clientPath) {
|
|
14381
|
-
const facts = {
|
|
14382
|
-
hasMount: false,
|
|
14383
|
-
hasClient: false,
|
|
14384
|
-
bodyEndOffset: null,
|
|
14385
|
-
htmlEndOffset: null
|
|
14386
|
-
};
|
|
14387
|
-
let body = null;
|
|
14388
|
-
visitElements(document2, (element) => {
|
|
14389
|
-
if (element.namespaceURI !== "http://www.w3.org/1999/xhtml") return;
|
|
14390
|
-
const tagName = element.tagName.toLowerCase();
|
|
14391
|
-
if (tagName === "body") body = element;
|
|
14392
|
-
if (tagName === "script" && (attributeValue(element, CLIENT_MARKER) !== null || attributeValue(element, "src") === clientPath)) {
|
|
14393
|
-
facts.hasClient = true;
|
|
14394
|
-
}
|
|
14395
|
-
const endOffset = element.sourceCodeLocation?.endTag?.startOffset;
|
|
14396
|
-
if (tagName === "body" && endOffset !== void 0) facts.bodyEndOffset = endOffset;
|
|
14397
|
-
if (tagName === "html" && endOffset !== void 0) facts.htmlEndOffset = endOffset;
|
|
14398
|
-
});
|
|
14399
|
-
if (body) {
|
|
14400
|
-
visitElements(body, (element) => {
|
|
14401
|
-
if (element !== body && attributeValue(element, "id") === NUDGE_UI_MOUNT_ID) {
|
|
14402
|
-
facts.hasMount = true;
|
|
14403
|
-
}
|
|
14404
|
-
});
|
|
14405
|
-
}
|
|
14406
|
-
return facts;
|
|
14407
|
-
}
|
|
14408
|
-
function visitElements(parent, visit) {
|
|
14409
|
-
for (const child of parent.childNodes) {
|
|
14410
|
-
if (!("tagName" in child) || typeof child.tagName !== "string") continue;
|
|
14411
|
-
if (child.tagName.toLowerCase() === "template") continue;
|
|
14412
|
-
visit(child);
|
|
14413
|
-
visitElements(child, visit);
|
|
14414
|
-
}
|
|
14415
|
-
}
|
|
14416
|
-
function attributeValue(element, name) {
|
|
14417
|
-
return element.attrs.find((attribute) => attribute.name === name)?.value ?? null;
|
|
14418
|
-
}
|
|
14419
|
-
function escapeAttributeValue2(value) {
|
|
14420
|
-
return value.replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<").replaceAll(">", ">");
|
|
14421
|
-
}
|
|
14422
|
-
|
|
14423
14681
|
// src/hosts/projectBridge.ts
|
|
14424
14682
|
import { existsSync as existsSync2 } from "node:fs";
|
|
14425
14683
|
import { createRequire as createRequire2 } from "node:module";
|
|
14426
|
-
import { dirname as dirname2, join as
|
|
14684
|
+
import { dirname as dirname2, join as join3, parse as parse2 } from "node:path";
|
|
14427
14685
|
import { pathToFileURL } from "node:url";
|
|
14428
14686
|
var runningBridges = /* @__PURE__ */ new Map();
|
|
14429
14687
|
async function startOptionalProjectBridge(input) {
|
|
@@ -14444,7 +14702,7 @@ async function launchOptionalProjectBridge(input, key) {
|
|
|
14444
14702
|
runningBridges.delete(key);
|
|
14445
14703
|
return null;
|
|
14446
14704
|
}
|
|
14447
|
-
modulePath = createRequire2(
|
|
14705
|
+
modulePath = createRequire2(join3(input.appRoot, "package.json")).resolve("@nudge-ui/mcp/project");
|
|
14448
14706
|
} catch {
|
|
14449
14707
|
runningBridges.delete(key);
|
|
14450
14708
|
return null;
|
|
@@ -14464,6 +14722,7 @@ async function launchOptionalProjectBridge(input, key) {
|
|
|
14464
14722
|
await runtime.close().catch(() => void 0);
|
|
14465
14723
|
throw new Error("the project bridge returned a different project or origin");
|
|
14466
14724
|
}
|
|
14725
|
+
input.info?.(`[nudge-ui] project bridge ready for ${input.projectId}`);
|
|
14467
14726
|
let closed = false;
|
|
14468
14727
|
return {
|
|
14469
14728
|
browser: { baseUrl: runtime.browser.bridgeUrl, autoConnect: true },
|
|
@@ -14485,24 +14744,24 @@ function isPnpRuntime() {
|
|
|
14485
14744
|
return typeof process.versions.pnp === "string";
|
|
14486
14745
|
}
|
|
14487
14746
|
function hasProjectInstalledMcp(appRoot) {
|
|
14488
|
-
let
|
|
14489
|
-
const root2 = parse2(
|
|
14747
|
+
let directory2 = appRoot;
|
|
14748
|
+
const root2 = parse2(directory2).root;
|
|
14490
14749
|
for (; ; ) {
|
|
14491
|
-
if (existsSync2(
|
|
14492
|
-
if (
|
|
14493
|
-
|
|
14750
|
+
if (existsSync2(join3(directory2, "node_modules", "@nudge-ui", "mcp", "package.json"))) return true;
|
|
14751
|
+
if (directory2 === root2) return false;
|
|
14752
|
+
directory2 = dirname2(directory2);
|
|
14494
14753
|
}
|
|
14495
14754
|
}
|
|
14496
14755
|
|
|
14497
14756
|
// src/project/tokens.ts
|
|
14498
|
-
import { createHash } from "node:crypto";
|
|
14757
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
14499
14758
|
import {
|
|
14500
14759
|
readFile as readUtf8File,
|
|
14501
14760
|
readdir,
|
|
14502
|
-
realpath,
|
|
14761
|
+
realpath as realpath2,
|
|
14503
14762
|
stat
|
|
14504
14763
|
} from "node:fs/promises";
|
|
14505
|
-
import { extname, isAbsolute, join as
|
|
14764
|
+
import { extname, isAbsolute as isAbsolute2, join as join4, relative as relative2, resolve, sep as sep2 } from "node:path";
|
|
14506
14765
|
|
|
14507
14766
|
// ../../node_modules/.pnpm/postcss@8.5.26/node_modules/postcss/lib/postcss.mjs
|
|
14508
14767
|
var import_postcss = __toESM(require_postcss(), 1);
|
|
@@ -15016,7 +15275,7 @@ var EMPTY_PROJECT_TOKEN_SNAPSHOT = {
|
|
|
15016
15275
|
async function createProjectTokenSnapshot(options) {
|
|
15017
15276
|
const rootDirectory = await canonicalRoot(options.rootDirectory);
|
|
15018
15277
|
const additionalRoots = (await Promise.all(
|
|
15019
|
-
(options.additionalRootDirectories ?? []).map((
|
|
15278
|
+
(options.additionalRootDirectories ?? []).map((directory2) => canonicalOptionalRoot(directory2))
|
|
15020
15279
|
)).filter((root2) => root2 !== null);
|
|
15021
15280
|
const scanRoots = [rootDirectory, ...additionalRoots.filter((root2) => root2 !== rootDirectory)];
|
|
15022
15281
|
const discovered = await Promise.all(
|
|
@@ -15026,12 +15285,12 @@ async function createProjectTokenSnapshot(options) {
|
|
|
15026
15285
|
const seenFiles = /* @__PURE__ */ new Set();
|
|
15027
15286
|
for (let index = 0; index < discovered.length; index += 1) {
|
|
15028
15287
|
for (const artifact of discovered[index] ?? []) {
|
|
15029
|
-
const canonicalPath = await
|
|
15288
|
+
const canonicalPath = await realpath2(artifact.absolutePath).catch(() => artifact.absolutePath);
|
|
15030
15289
|
if (seenFiles.has(canonicalPath)) continue;
|
|
15031
15290
|
seenFiles.add(canonicalPath);
|
|
15032
15291
|
artifacts.push({
|
|
15033
15292
|
...artifact,
|
|
15034
|
-
projectPath: index === 0 ? artifact.projectPath :
|
|
15293
|
+
projectPath: index === 0 ? artifact.projectPath : relative2(rootDirectory, artifact.absolutePath).split(sep2).join("/")
|
|
15035
15294
|
});
|
|
15036
15295
|
}
|
|
15037
15296
|
}
|
|
@@ -15074,32 +15333,32 @@ async function createProjectTokenSnapshot(options) {
|
|
|
15074
15333
|
tokenGeneration
|
|
15075
15334
|
};
|
|
15076
15335
|
}
|
|
15077
|
-
async function discoverProjectCssArtifacts(rootDirectory,
|
|
15336
|
+
async function discoverProjectCssArtifacts(rootDirectory, readFile2 = (absolutePath) => readUtf8File(absolutePath, "utf8")) {
|
|
15078
15337
|
const root2 = await canonicalRoot(rootDirectory);
|
|
15079
15338
|
const artifacts = [];
|
|
15080
15339
|
const visitedDirectories = /* @__PURE__ */ new Set();
|
|
15081
15340
|
const visitedFiles = /* @__PURE__ */ new Set();
|
|
15082
|
-
await walkDirectory(root2, root2, visitedDirectories, visitedFiles, artifacts,
|
|
15341
|
+
await walkDirectory(root2, root2, visitedDirectories, visitedFiles, artifacts, readFile2);
|
|
15083
15342
|
artifacts.sort((a, b) => comparePosixStrings(a.projectPath, b.projectPath));
|
|
15084
15343
|
return artifacts;
|
|
15085
15344
|
}
|
|
15086
|
-
async function walkDirectory(rootDirectory,
|
|
15087
|
-
const canonicalDirectoryPath = await canonicalWithinRoot(rootDirectory,
|
|
15345
|
+
async function walkDirectory(rootDirectory, directory2, visitedDirectories, visitedFiles, artifacts, readFile2) {
|
|
15346
|
+
const canonicalDirectoryPath = await canonicalWithinRoot(rootDirectory, directory2);
|
|
15088
15347
|
if (!canonicalDirectoryPath || visitedDirectories.has(canonicalDirectoryPath)) return;
|
|
15089
|
-
const projectDirectoryPath =
|
|
15090
|
-
const canonicalProjectDirectoryPath =
|
|
15348
|
+
const projectDirectoryPath = relative2(rootDirectory, directory2).split(sep2).join("/");
|
|
15349
|
+
const canonicalProjectDirectoryPath = relative2(rootDirectory, canonicalDirectoryPath).split(sep2).join("/");
|
|
15091
15350
|
if (isSensitiveProjectPath(projectDirectoryPath) || isSensitiveProjectPath(canonicalProjectDirectoryPath)) return;
|
|
15092
15351
|
visitedDirectories.add(canonicalDirectoryPath);
|
|
15093
15352
|
let entries;
|
|
15094
15353
|
try {
|
|
15095
|
-
entries = await readdir(
|
|
15354
|
+
entries = await readdir(directory2, { withFileTypes: true });
|
|
15096
15355
|
} catch {
|
|
15097
15356
|
return;
|
|
15098
15357
|
}
|
|
15099
15358
|
entries.sort((a, b) => comparePosixStrings(a.name, b.name));
|
|
15100
15359
|
for (const entry of entries) {
|
|
15101
15360
|
if (entry.isDirectory() && isExcludedDirectoryName(entry.name)) continue;
|
|
15102
|
-
const absolutePath =
|
|
15361
|
+
const absolutePath = join4(directory2, entry.name);
|
|
15103
15362
|
const canonicalPath = await canonicalWithinRoot(rootDirectory, absolutePath);
|
|
15104
15363
|
if (!canonicalPath) continue;
|
|
15105
15364
|
let stats;
|
|
@@ -15116,20 +15375,20 @@ async function walkDirectory(rootDirectory, directory, visitedDirectories, visit
|
|
|
15116
15375
|
visitedDirectories,
|
|
15117
15376
|
visitedFiles,
|
|
15118
15377
|
artifacts,
|
|
15119
|
-
|
|
15378
|
+
readFile2
|
|
15120
15379
|
);
|
|
15121
15380
|
continue;
|
|
15122
15381
|
}
|
|
15123
15382
|
if (!stats.isFile() || extname(entry.name).toLowerCase() !== ".css") continue;
|
|
15124
15383
|
if (visitedFiles.has(canonicalPath)) continue;
|
|
15125
15384
|
visitedFiles.add(canonicalPath);
|
|
15126
|
-
const projectPath =
|
|
15127
|
-
const canonicalProjectPath2 =
|
|
15385
|
+
const projectPath = relative2(rootDirectory, absolutePath).split(sep2).join("/");
|
|
15386
|
+
const canonicalProjectPath2 = relative2(rootDirectory, canonicalPath).split(sep2).join("/");
|
|
15128
15387
|
if (isSensitiveProjectPath(projectPath) || isSensitiveProjectPath(canonicalProjectPath2)) {
|
|
15129
15388
|
continue;
|
|
15130
15389
|
}
|
|
15131
15390
|
try {
|
|
15132
|
-
const content = await
|
|
15391
|
+
const content = await readFile2(absolutePath);
|
|
15133
15392
|
artifacts.push({ absolutePath, projectPath, content });
|
|
15134
15393
|
} catch (error) {
|
|
15135
15394
|
artifacts.push({
|
|
@@ -15141,7 +15400,7 @@ async function walkDirectory(rootDirectory, directory, visitedDirectories, visit
|
|
|
15141
15400
|
}
|
|
15142
15401
|
}
|
|
15143
15402
|
async function canonicalRoot(rootDirectory) {
|
|
15144
|
-
const root2 = await
|
|
15403
|
+
const root2 = await realpath2(resolve(rootDirectory));
|
|
15145
15404
|
if (!(await stat(root2)).isDirectory()) {
|
|
15146
15405
|
throw new Error(`Standalone root is not a directory: ${rootDirectory}`);
|
|
15147
15406
|
}
|
|
@@ -15156,9 +15415,9 @@ async function canonicalOptionalRoot(rootDirectory) {
|
|
|
15156
15415
|
}
|
|
15157
15416
|
async function canonicalWithinRoot(rootDirectory, candidate) {
|
|
15158
15417
|
try {
|
|
15159
|
-
const canonical = await
|
|
15160
|
-
const pathFromRoot =
|
|
15161
|
-
if (pathFromRoot === "" || !pathFromRoot.startsWith(`..${
|
|
15418
|
+
const canonical = await realpath2(candidate);
|
|
15419
|
+
const pathFromRoot = relative2(rootDirectory, canonical);
|
|
15420
|
+
if (pathFromRoot === "" || !pathFromRoot.startsWith(`..${sep2}`) && pathFromRoot !== ".." && !isAbsolute2(pathFromRoot)) {
|
|
15162
15421
|
return canonical;
|
|
15163
15422
|
}
|
|
15164
15423
|
} catch {
|
|
@@ -15186,7 +15445,7 @@ function deterministicGeneration(artifacts, inventoryGeneration, label) {
|
|
|
15186
15445
|
content: artifact.content,
|
|
15187
15446
|
readError: artifact.readError
|
|
15188
15447
|
}));
|
|
15189
|
-
const digest =
|
|
15448
|
+
const digest = createHash2("sha256").update(`${facts.join("\n")}
|
|
15190
15449
|
${inventoryGeneration}`).digest("hex").slice(0, 24);
|
|
15191
15450
|
return `${label}:${digest}`;
|
|
15192
15451
|
}
|
|
@@ -15198,7 +15457,7 @@ function comparePosixStrings(a, b) {
|
|
|
15198
15457
|
import { watch } from "node:fs";
|
|
15199
15458
|
import { readdir as readdir2 } from "node:fs/promises";
|
|
15200
15459
|
import { realpathSync, statSync } from "node:fs";
|
|
15201
|
-
import { dirname as dirname3, isAbsolute as
|
|
15460
|
+
import { dirname as dirname3, isAbsolute as isAbsolute3, join as join5, relative as relative3, resolve as resolve2, sep as sep3 } from "node:path";
|
|
15202
15461
|
function createProjectFileWatcher(options) {
|
|
15203
15462
|
const rootDirectory = realpathSync(resolve2(options.rootDirectory));
|
|
15204
15463
|
const debounceMs = Math.max(0, options.debounceMs ?? 60);
|
|
@@ -15228,30 +15487,30 @@ function createProjectFileWatcher(options) {
|
|
|
15228
15487
|
pending.clear();
|
|
15229
15488
|
void Promise.resolve(options.onSettled(changes)).catch(reportError);
|
|
15230
15489
|
};
|
|
15231
|
-
const closeDirectory = (
|
|
15232
|
-
const entry = watches.get(
|
|
15490
|
+
const closeDirectory = (directory2) => {
|
|
15491
|
+
const entry = watches.get(directory2);
|
|
15233
15492
|
if (!entry) return;
|
|
15234
|
-
watches.delete(
|
|
15493
|
+
watches.delete(directory2);
|
|
15235
15494
|
entry.watcher.close();
|
|
15236
15495
|
};
|
|
15237
|
-
const closeDescendants = (
|
|
15496
|
+
const closeDescendants = (directory2) => {
|
|
15238
15497
|
for (const watchedDirectory of [...watches.keys()]) {
|
|
15239
|
-
if (watchedDirectory ===
|
|
15498
|
+
if (watchedDirectory === directory2 || watchedDirectory.startsWith(`${directory2}${sep3}`)) {
|
|
15240
15499
|
closeDirectory(watchedDirectory);
|
|
15241
15500
|
}
|
|
15242
15501
|
}
|
|
15243
15502
|
};
|
|
15244
|
-
const watchDirectory = (
|
|
15245
|
-
if (closed || !isProjectDirectory(rootDirectory,
|
|
15246
|
-
const canonicalDirectory2 = canonicalProjectPath(rootDirectory,
|
|
15503
|
+
const watchDirectory = (directory2) => {
|
|
15504
|
+
if (closed || !isProjectDirectory(rootDirectory, directory2)) return;
|
|
15505
|
+
const canonicalDirectory2 = canonicalProjectPath(rootDirectory, directory2);
|
|
15247
15506
|
if (!canonicalDirectory2 || [...watches.values()].some(
|
|
15248
15507
|
(entry) => entry.canonicalDirectory === canonicalDirectory2
|
|
15249
15508
|
)) return;
|
|
15250
15509
|
let directoryWatcher;
|
|
15251
15510
|
try {
|
|
15252
|
-
directoryWatcher = watch(
|
|
15511
|
+
directoryWatcher = watch(directory2, { persistent: true }, (eventType, filename) => {
|
|
15253
15512
|
const changedName = filename?.toString();
|
|
15254
|
-
const changedPath = changedName ?
|
|
15513
|
+
const changedPath = changedName ? join5(directory2, changedName) : directory2;
|
|
15255
15514
|
if (!isProjectPath(rootDirectory, changedPath)) return;
|
|
15256
15515
|
if (isProjectDirectory(rootDirectory, changedPath)) watchDirectory(changedPath);
|
|
15257
15516
|
else if (!exists(changedPath)) closeDescendants(changedPath);
|
|
@@ -15262,17 +15521,17 @@ function createProjectFileWatcher(options) {
|
|
|
15262
15521
|
reportError(error);
|
|
15263
15522
|
return;
|
|
15264
15523
|
}
|
|
15265
|
-
watches.set(
|
|
15524
|
+
watches.set(directory2, { directory: directory2, canonicalDirectory: canonicalDirectory2, watcher: directoryWatcher });
|
|
15266
15525
|
pendingScans += 1;
|
|
15267
|
-
scanQueue = scanQueue.then(() => scanSubdirectories(
|
|
15526
|
+
scanQueue = scanQueue.then(() => scanSubdirectories(directory2)).catch(reportError).finally(() => {
|
|
15268
15527
|
pendingScans -= 1;
|
|
15269
15528
|
if (pendingScans === 0) resolveReady?.();
|
|
15270
15529
|
});
|
|
15271
15530
|
};
|
|
15272
|
-
const scanSubdirectories = async (
|
|
15531
|
+
const scanSubdirectories = async (directory2) => {
|
|
15273
15532
|
let entries;
|
|
15274
15533
|
try {
|
|
15275
|
-
entries = await readdir2(
|
|
15534
|
+
entries = await readdir2(directory2, { withFileTypes: true });
|
|
15276
15535
|
} catch {
|
|
15277
15536
|
return;
|
|
15278
15537
|
}
|
|
@@ -15280,7 +15539,7 @@ function createProjectFileWatcher(options) {
|
|
|
15280
15539
|
for (const entry of entries) {
|
|
15281
15540
|
if (closed) return;
|
|
15282
15541
|
if (!entry.isDirectory() || isExcludedDirectoryName(entry.name)) continue;
|
|
15283
|
-
const child =
|
|
15542
|
+
const child = join5(directory2, entry.name);
|
|
15284
15543
|
if (!isProjectPath(rootDirectory, child)) continue;
|
|
15285
15544
|
watchDirectory(child);
|
|
15286
15545
|
}
|
|
@@ -15304,7 +15563,7 @@ function createProjectFileWatcher(options) {
|
|
|
15304
15563
|
timer = null;
|
|
15305
15564
|
}
|
|
15306
15565
|
pending.clear();
|
|
15307
|
-
for (const
|
|
15566
|
+
for (const directory2 of [...watches.keys()]) closeDirectory(directory2);
|
|
15308
15567
|
await scanQueue;
|
|
15309
15568
|
}
|
|
15310
15569
|
};
|
|
@@ -15342,24 +15601,24 @@ function isProjectPath(rootDirectory, path) {
|
|
|
15342
15601
|
function canonicalProjectPath(rootDirectory, path) {
|
|
15343
15602
|
try {
|
|
15344
15603
|
const canonical = realpathSync(path);
|
|
15345
|
-
return isWithin(rootDirectory, canonical) && !isSensitiveProjectPath(
|
|
15604
|
+
return isWithin(rootDirectory, canonical) && !isSensitiveProjectPath(relative3(rootDirectory, canonical).split(sep3).join("/")) ? canonical : null;
|
|
15346
15605
|
} catch {
|
|
15347
15606
|
const parent = dirname3(path);
|
|
15348
15607
|
if (parent === path) return null;
|
|
15349
15608
|
try {
|
|
15350
15609
|
const canonicalParent = realpathSync(parent);
|
|
15351
|
-
return isWithin(rootDirectory, canonicalParent) && !isSensitiveProjectPath(
|
|
15610
|
+
return isWithin(rootDirectory, canonicalParent) && !isSensitiveProjectPath(relative3(rootDirectory, canonicalParent).split(sep3).join("/")) ? canonicalParent : null;
|
|
15352
15611
|
} catch {
|
|
15353
15612
|
return null;
|
|
15354
15613
|
}
|
|
15355
15614
|
}
|
|
15356
15615
|
}
|
|
15357
15616
|
function isExcludedDirectory(rootDirectory, path) {
|
|
15358
|
-
return
|
|
15617
|
+
return relative3(rootDirectory, resolve2(path)).split(sep3).some((segment) => isExcludedDirectoryName(segment));
|
|
15359
15618
|
}
|
|
15360
15619
|
function isWithin(rootDirectory, candidate) {
|
|
15361
|
-
const pathFromRoot =
|
|
15362
|
-
return pathFromRoot === "" || !pathFromRoot.startsWith(`..${
|
|
15620
|
+
const pathFromRoot = relative3(rootDirectory, candidate);
|
|
15621
|
+
return pathFromRoot === "" || !pathFromRoot.startsWith(`..${sep3}`) && pathFromRoot !== ".." && !isAbsolute3(pathFromRoot);
|
|
15363
15622
|
}
|
|
15364
15623
|
function comparePosixStrings2(a, b) {
|
|
15365
15624
|
return Buffer.from(a, "utf8").compare(Buffer.from(b, "utf8"));
|
|
@@ -15380,15 +15639,15 @@ function createStandaloneServer(options) {
|
|
|
15380
15639
|
validatePort(port);
|
|
15381
15640
|
const clientPath = options.clientPath;
|
|
15382
15641
|
const projectId = options.projectId ?? createStandaloneProjectId(rootDirectory);
|
|
15383
|
-
let
|
|
15642
|
+
let revision2 = 0;
|
|
15384
15643
|
let manifest = createStandaloneRuntimeManifest(
|
|
15385
15644
|
projectId,
|
|
15386
15645
|
EMPTY_PROJECT_TOKEN_SNAPSHOT,
|
|
15387
|
-
|
|
15646
|
+
revision2
|
|
15388
15647
|
);
|
|
15389
15648
|
let projectBridge = null;
|
|
15390
15649
|
const initialTokens = createProjectTokenSnapshot({ rootDirectory, generationLabel: "static-html" }).then((tokens) => {
|
|
15391
|
-
manifest = createStandaloneRuntimeManifest(projectId, tokens,
|
|
15650
|
+
manifest = createStandaloneRuntimeManifest(projectId, tokens, revision2);
|
|
15392
15651
|
return tokens;
|
|
15393
15652
|
});
|
|
15394
15653
|
void initialTokens.catch(() => void 0);
|
|
@@ -15404,7 +15663,7 @@ function createStandaloneServer(options) {
|
|
|
15404
15663
|
};
|
|
15405
15664
|
const notifyReload = () => {
|
|
15406
15665
|
const payload = `event: reload
|
|
15407
|
-
data: ${JSON.stringify({ revision })}
|
|
15666
|
+
data: ${JSON.stringify({ revision: revision2 })}
|
|
15408
15667
|
|
|
15409
15668
|
`;
|
|
15410
15669
|
for (const client of [...reloadClients]) {
|
|
@@ -15424,10 +15683,10 @@ data: ${JSON.stringify({ revision })}
|
|
|
15424
15683
|
changeQueue = changeQueue.then(async () => {
|
|
15425
15684
|
const tokens = await createProjectTokenSnapshot({ rootDirectory, generationLabel: "static-html" });
|
|
15426
15685
|
manifest = {
|
|
15427
|
-
...createStandaloneRuntimeManifest(projectId, tokens,
|
|
15686
|
+
...createStandaloneRuntimeManifest(projectId, tokens, revision2 + 1),
|
|
15428
15687
|
...projectBridge ? { agentBridge: projectBridge.browser } : {}
|
|
15429
15688
|
};
|
|
15430
|
-
|
|
15689
|
+
revision2 += 1;
|
|
15431
15690
|
notifyReload();
|
|
15432
15691
|
}).catch((error) => {
|
|
15433
15692
|
console.warn(
|
|
@@ -15498,6 +15757,7 @@ data: ${JSON.stringify({ revision })}
|
|
|
15498
15757
|
appRoot: rootDirectory,
|
|
15499
15758
|
projectId,
|
|
15500
15759
|
origin: address.url.replace(/\/$/, ""),
|
|
15760
|
+
info: (message) => console.info(message),
|
|
15501
15761
|
warn: (message) => console.warn(message)
|
|
15502
15762
|
}).then((bridge) => {
|
|
15503
15763
|
projectBridge = bridge;
|
|
@@ -15561,7 +15821,7 @@ function resolveDecodedStaticFile(root2, decodedPath) {
|
|
|
15561
15821
|
let filePath = canonicalCandidate;
|
|
15562
15822
|
const stats = statSync2(filePath);
|
|
15563
15823
|
if (stats.isDirectory()) {
|
|
15564
|
-
const indexCandidate =
|
|
15824
|
+
const indexCandidate = join6(filePath, "index.html");
|
|
15565
15825
|
const canonicalIndex = canonicalExistingAncestor(indexCandidate);
|
|
15566
15826
|
if (!canonicalIndex || !isWithin2(root2, canonicalIndex) || !existsSync3(indexCandidate)) {
|
|
15567
15827
|
return null;
|
|
@@ -15571,13 +15831,13 @@ function resolveDecodedStaticFile(root2, decodedPath) {
|
|
|
15571
15831
|
} else if (!stats.isFile()) {
|
|
15572
15832
|
return null;
|
|
15573
15833
|
}
|
|
15574
|
-
const relativePath =
|
|
15834
|
+
const relativePath = relative4(root2, filePath).split("\\").join("/");
|
|
15575
15835
|
if (isSensitiveProjectPath(relativePath)) return null;
|
|
15576
15836
|
return { absolutePath: filePath, projectPath: relativePath };
|
|
15577
15837
|
}
|
|
15578
15838
|
function createStandaloneProjectId(rootDirectory) {
|
|
15579
15839
|
const canonicalRoot2 = canonicalDirectory(rootDirectory);
|
|
15580
|
-
const digest =
|
|
15840
|
+
const digest = createHash3("sha256").update(canonicalRoot2).digest("hex").slice(0, 24);
|
|
15581
15841
|
return `static-html:${digest}`;
|
|
15582
15842
|
}
|
|
15583
15843
|
function contentTypeForPath(filePath) {
|
|
@@ -15587,15 +15847,15 @@ function contentTypeForPath(filePath) {
|
|
|
15587
15847
|
function isReservedNudgeUiRoute2(pathname) {
|
|
15588
15848
|
return pathname === NUDGE_UI_ROUTE_PREFIX.slice(0, -1) || pathname.startsWith(NUDGE_UI_ROUTE_PREFIX);
|
|
15589
15849
|
}
|
|
15590
|
-
function canonicalDirectory(
|
|
15591
|
-
const canonical = canonicalDirectoryOrNull(
|
|
15592
|
-
if (!canonical) throw new Error(`Standalone root is not a readable directory: ${
|
|
15850
|
+
function canonicalDirectory(directory2) {
|
|
15851
|
+
const canonical = canonicalDirectoryOrNull(directory2);
|
|
15852
|
+
if (!canonical) throw new Error(`Standalone root is not a readable directory: ${directory2}`);
|
|
15593
15853
|
return canonical;
|
|
15594
15854
|
}
|
|
15595
|
-
function canonicalDirectoryOrNull(
|
|
15596
|
-
if (!
|
|
15855
|
+
function canonicalDirectoryOrNull(directory2) {
|
|
15856
|
+
if (!isAbsolute4(directory2)) return null;
|
|
15597
15857
|
try {
|
|
15598
|
-
const canonical = realpathSync2(
|
|
15858
|
+
const canonical = realpathSync2(directory2);
|
|
15599
15859
|
return statSync2(canonical).isDirectory() ? canonical : null;
|
|
15600
15860
|
} catch {
|
|
15601
15861
|
return null;
|
|
@@ -15653,11 +15913,12 @@ function isMissingPathError(error) {
|
|
|
15653
15913
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
15654
15914
|
}
|
|
15655
15915
|
function isWithin2(root2, candidate) {
|
|
15656
|
-
const pathFromRoot =
|
|
15657
|
-
return pathFromRoot === "" || !pathFromRoot.startsWith("..") && !
|
|
15916
|
+
const pathFromRoot = relative4(root2, candidate);
|
|
15917
|
+
return pathFromRoot === "" || !pathFromRoot.startsWith("..") && !isAbsolute4(pathFromRoot);
|
|
15658
15918
|
}
|
|
15659
15919
|
async function handleRequest(input) {
|
|
15660
15920
|
const { request, response } = input;
|
|
15921
|
+
if (await handleHtmlArtifactRequest(request, response, input.rootDirectory)) return;
|
|
15661
15922
|
if (request.method !== "GET" && request.method !== "HEAD") {
|
|
15662
15923
|
sendText(response, 405, "Method Not Allowed", { Allow: "GET, HEAD" });
|
|
15663
15924
|
return;
|
|
@@ -15672,8 +15933,8 @@ async function handleRequest(input) {
|
|
|
15672
15933
|
return;
|
|
15673
15934
|
}
|
|
15674
15935
|
if (isNudgeUiEditorDocumentRequest(request.url ?? "/", request.method, request.headers)) {
|
|
15675
|
-
const
|
|
15676
|
-
sendBody(response, 200,
|
|
15936
|
+
const body3 = request.method === "HEAD" ? Buffer.alloc(0) : Buffer.from(createNudgeUiEditorDocument(), "utf8");
|
|
15937
|
+
sendBody(response, 200, body3, "text/html; charset=utf-8", { "Cache-Control": "no-store" });
|
|
15677
15938
|
return;
|
|
15678
15939
|
}
|
|
15679
15940
|
const resolution = resolveDecodedStaticFile(input.rootDirectory, decodedPath);
|
|
@@ -15684,7 +15945,7 @@ async function handleRequest(input) {
|
|
|
15684
15945
|
const isHtml = HTML_EXTENSIONS.has(extname2(resolution.projectPath).toLowerCase());
|
|
15685
15946
|
const contentType = contentTypeForPath(resolution.projectPath);
|
|
15686
15947
|
if (request.method === "HEAD") {
|
|
15687
|
-
const
|
|
15948
|
+
const body3 = await readProjectFile(resolution.absolutePath);
|
|
15688
15949
|
if (isHtml) {
|
|
15689
15950
|
response.writeHead(200, {
|
|
15690
15951
|
"Content-Type": contentType,
|
|
@@ -15693,25 +15954,25 @@ async function handleRequest(input) {
|
|
|
15693
15954
|
});
|
|
15694
15955
|
response.end();
|
|
15695
15956
|
} else {
|
|
15696
|
-
sendBody(response, 200,
|
|
15957
|
+
sendBody(response, 200, body3, contentType);
|
|
15697
15958
|
}
|
|
15698
15959
|
return;
|
|
15699
15960
|
}
|
|
15700
|
-
let
|
|
15961
|
+
let body2 = await readProjectFile(resolution.absolutePath);
|
|
15701
15962
|
if (isHtml) {
|
|
15702
|
-
|
|
15963
|
+
body2 = instrumentHtmlResponse(body2, resolution.projectPath);
|
|
15703
15964
|
}
|
|
15704
|
-
sendBody(response, 200,
|
|
15965
|
+
sendBody(response, 200, body2, contentType, isHtml ? { "Cache-Control": "no-cache" } : {});
|
|
15705
15966
|
}
|
|
15706
|
-
function instrumentHtmlResponse(
|
|
15967
|
+
function instrumentHtmlResponse(body2, projectPath) {
|
|
15707
15968
|
let source;
|
|
15708
15969
|
try {
|
|
15709
|
-
source = strictUtf8Decoder.decode(
|
|
15970
|
+
source = strictUtf8Decoder.decode(body2);
|
|
15710
15971
|
} catch {
|
|
15711
15972
|
console.warn(
|
|
15712
15973
|
`Nudge UI served ${projectPath} without instrumentation because it is not valid UTF-8.`
|
|
15713
15974
|
);
|
|
15714
|
-
return
|
|
15975
|
+
return body2;
|
|
15715
15976
|
}
|
|
15716
15977
|
const identified = instrumentSourceHtml(source, projectPath);
|
|
15717
15978
|
const bootstrapped = injectStandaloneBootstrap(identified.html);
|
|
@@ -15720,23 +15981,23 @@ function instrumentHtmlResponse(body, projectPath) {
|
|
|
15720
15981
|
var strictUtf8Decoder = new TextDecoder("utf-8", { fatal: true });
|
|
15721
15982
|
async function handleNudgeUiRoute(input, pathname) {
|
|
15722
15983
|
if (pathname === NUDGE_UI_MANIFEST_PATH) {
|
|
15723
|
-
const
|
|
15724
|
-
sendBody(input.response, 200,
|
|
15984
|
+
const body2 = Buffer.from(JSON.stringify(input.getManifest()), "utf8");
|
|
15985
|
+
sendBody(input.response, 200, body2, "application/json; charset=utf-8", {
|
|
15725
15986
|
"Cache-Control": "no-store"
|
|
15726
15987
|
});
|
|
15727
15988
|
return;
|
|
15728
15989
|
}
|
|
15729
15990
|
if (pathname === NUDGE_UI_EDITOR_PATH) {
|
|
15730
|
-
const
|
|
15731
|
-
sendBody(input.response, 200,
|
|
15991
|
+
const body2 = input.request.method === "HEAD" ? Buffer.alloc(0) : Buffer.from(createNudgeUiEditorDocument(), "utf8");
|
|
15992
|
+
sendBody(input.response, 200, body2, "text/html; charset=utf-8", {
|
|
15732
15993
|
"Cache-Control": "no-store"
|
|
15733
15994
|
});
|
|
15734
15995
|
return;
|
|
15735
15996
|
}
|
|
15736
15997
|
if (pathname === NUDGE_UI_CLIENT_PATH) {
|
|
15737
15998
|
try {
|
|
15738
|
-
const
|
|
15739
|
-
sendBody(input.response, 200,
|
|
15999
|
+
const body2 = await readFileFromDescriptor(input.clientPath ?? resolveDefaultClientPath());
|
|
16000
|
+
sendBody(input.response, 200, body2, "text/javascript; charset=utf-8", {
|
|
15740
16001
|
"Cache-Control": "no-cache"
|
|
15741
16002
|
});
|
|
15742
16003
|
} catch {
|
|
@@ -15813,14 +16074,14 @@ function validatePort(port) {
|
|
|
15813
16074
|
function sendText(response, status, text, headers = {}) {
|
|
15814
16075
|
sendBody(response, status, Buffer.from(text, "utf8"), "text/plain; charset=utf-8", headers);
|
|
15815
16076
|
}
|
|
15816
|
-
function sendBody(response, status,
|
|
16077
|
+
function sendBody(response, status, body2, contentType, headers = {}) {
|
|
15817
16078
|
response.writeHead(status, {
|
|
15818
16079
|
"Content-Type": contentType,
|
|
15819
|
-
"Content-Length":
|
|
16080
|
+
"Content-Length": body2.byteLength,
|
|
15820
16081
|
"X-Content-Type-Options": "nosniff",
|
|
15821
16082
|
...headers
|
|
15822
16083
|
});
|
|
15823
|
-
if (response.req?.method !== "HEAD") response.end(
|
|
16084
|
+
if (response.req?.method !== "HEAD") response.end(body2);
|
|
15824
16085
|
else response.end();
|
|
15825
16086
|
}
|
|
15826
16087
|
var MIME_TYPES2 = {
|
|
@@ -15856,7 +16117,7 @@ function parseServeArguments(args, currentDirectory = process.cwd()) {
|
|
|
15856
16117
|
if (args[0] !== "serve") {
|
|
15857
16118
|
throw new Error("Usage: nudge-ui serve [directory] [--port <port>] [--host <loopback>]");
|
|
15858
16119
|
}
|
|
15859
|
-
let
|
|
16120
|
+
let directory2 = ".";
|
|
15860
16121
|
let host = "127.0.0.1";
|
|
15861
16122
|
let port = 4173;
|
|
15862
16123
|
let directoryProvided = false;
|
|
@@ -15873,13 +16134,13 @@ function parseServeArguments(args, currentDirectory = process.cwd()) {
|
|
|
15873
16134
|
} else if (argument.startsWith("-")) {
|
|
15874
16135
|
throw new Error(`Unknown option: ${argument}`);
|
|
15875
16136
|
} else if (!directoryProvided) {
|
|
15876
|
-
|
|
16137
|
+
directory2 = argument;
|
|
15877
16138
|
directoryProvided = true;
|
|
15878
16139
|
} else {
|
|
15879
16140
|
throw new Error(`Unexpected argument: ${argument}`);
|
|
15880
16141
|
}
|
|
15881
16142
|
}
|
|
15882
|
-
return { rootDirectory: resolve4(currentDirectory,
|
|
16143
|
+
return { rootDirectory: resolve4(currentDirectory, directory2), host, port };
|
|
15883
16144
|
}
|
|
15884
16145
|
async function runServeCommand(options) {
|
|
15885
16146
|
const server = createStandaloneServer(options);
|