nudge-ui 0.2.2 → 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 -61
- 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 +38 -32
- package/dist/hosts/astro/integration.js +5 -1
- package/dist/hosts/astro/markdownIdentity.d.ts +28 -0
- package/dist/hosts/astro/markdownIdentity.js +81 -0
- package/dist/hosts/next/manifest.js +1 -1
- package/dist/hosts/next/sidecar.js +5 -1
- package/dist/hosts/static/manifest.js +1 -1
- package/dist/hosts/static/server.js +3 -0
- package/dist/hosts/vite/vite.d.ts +3 -0
- package/dist/hosts/vite/vite.js +24 -4
- package/dist/inspector/agent/McpConnectionDialog.js +13 -19
- package/dist/inspector/agent/activity.d.ts +18 -0
- package/dist/inspector/agent/activity.js +70 -0
- package/dist/inspector/agent/client.d.ts +2 -0
- package/dist/inspector/agent/client.js +29 -1
- package/dist/inspector/agent/connectionStatus.js +1 -1
- package/dist/inspector/agent/httpTransport.js +9 -2
- package/dist/inspector/agent/protocol.d.ts +6 -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 +152 -16
- 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 +225 -57
- 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 +21 -4
- package/dist/inspector/canvas/frameProtocol.js +3 -3
- package/dist/inspector/canvas/keyboardShortcuts.d.ts +3 -1
- package/dist/inspector/canvas/keyboardShortcuts.js +4 -4
- package/dist/inspector/canvas/layout.d.ts +52 -0
- package/dist/inspector/canvas/layout.js +106 -0
- package/dist/inspector/canvas/projection.d.ts +15 -5
- package/dist/inspector/canvas/projection.js +69 -13
- package/dist/inspector/canvas/rendererBootstrap.js +32 -4
- package/dist/inspector/canvas/rendererElementSelector.js +47 -6
- 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 +1 -1
- 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 +20 -27
- 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.js +21 -15
- package/dist/inspector/overlay/interactionStyles.js +3 -1
- package/dist/inspector/overlay/spacingGestures.d.ts +13 -1
- package/dist/inspector/overlay/spacingGestures.js +82 -5
- 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 +9 -0
- package/dist/inspector/runtime/runtimeConfig.js +24 -0
- package/dist/inspector/settings/SettingsDialog.js +21 -8
- 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 +46 -26
- package/dist/inspector/shell/CopyPromptButton.js +138 -89
- package/dist/inspector/shell/EmptyState.js +9 -8
- package/dist/inspector/shell/InspectorShell.js +13 -21
- 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/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 +7 -5
- 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 +2 -2
- package/dist/inspector/styleEditors/nudgeValue.js +36 -8
- package/dist/inspector/tokens/TokenField.d.ts +7 -0
- package/dist/inspector/tokens/TokenField.js +29 -21
- package/dist/inspector/tokens/TokenLabel.js +5 -14
- 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/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 +0 -2
- package/dist/inspector/ui/dragCursor.js +2 -10
- package/dist/inspector/ui/portalContainer.d.ts +2 -0
- package/dist/inspector/ui/portalContainer.js +6 -0
- package/dist/inspector/ui/styles.js +29 -21
- 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 +558 -311
- 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.js +3 -1
- package/dist/transport/routes.d.ts +2 -0
- package/dist/transport/routes.js +2 -0
- package/package.json +6 -2
- package/dist/inspector/changes/workspaceChanges.d.ts +0 -47
- package/dist/inspector/changes/workspaceChanges.js +0 -265
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,180 +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/environment.ts
|
|
14312
|
-
function readNudgeUiEnvironmentSwitch(env = process.env) {
|
|
14313
|
-
const value = env.NUDGE_UI?.trim().toLowerCase();
|
|
14314
|
-
if (value === "0" || value === "false" || value === "off") return "off";
|
|
14315
|
-
if (value === "1" || value === "true" || value === "on") return "on";
|
|
14316
|
-
return null;
|
|
14317
|
-
}
|
|
14318
|
-
function automationManifestFields(env = process.env) {
|
|
14319
|
-
return readNudgeUiEnvironmentSwitch(env) === "on" ? { inspectAutomatedBrowsers: true } : {};
|
|
14320
|
-
}
|
|
14321
|
-
|
|
14322
|
-
// src/hosts/static/manifest.ts
|
|
14323
|
-
function createStandaloneRuntimeManifest(projectId, tokenSnapshot = emptyTokenSnapshot(), revision = 0) {
|
|
14324
|
-
return {
|
|
14325
|
-
version: NUDGE_UI_MANIFEST_VERSION,
|
|
14326
|
-
revision,
|
|
14327
|
-
runtime: {
|
|
14328
|
-
projectId,
|
|
14329
|
-
host: "static-html",
|
|
14330
|
-
framework: "HTML",
|
|
14331
|
-
stylingSystem: "CSS custom properties",
|
|
14332
|
-
// Canvas shares the Vite host's controller/renderer runtime (ADR-0012):
|
|
14333
|
-
// every served document carries the bootstrap, so card iframes boot as
|
|
14334
|
-
// renderers without host-specific code.
|
|
14335
|
-
capabilities: { canvas: true, componentSemantics: false },
|
|
14336
|
-
tokenCatalog: tokenSnapshot.tokenCatalog,
|
|
14337
|
-
tokens: tokenSnapshot.tokens,
|
|
14338
|
-
tokenDiagnostics: tokenSnapshot.tokenDiagnostics,
|
|
14339
|
-
tokenGeneration: tokenSnapshot.tokenGeneration,
|
|
14340
|
-
componentContracts: []
|
|
14341
|
-
},
|
|
14342
|
-
document: {
|
|
14343
|
-
runtimeIdentity: "static-html",
|
|
14344
|
-
stylesheetOrder: "browser"
|
|
14345
|
-
},
|
|
14346
|
-
reload: {
|
|
14347
|
-
endpoint: NUDGE_UI_RELOAD_PATH,
|
|
14348
|
-
strategy: "reload-document",
|
|
14349
|
-
events: ["ready", "reload"]
|
|
14350
|
-
},
|
|
14351
|
-
...automationManifestFields()
|
|
14352
|
-
};
|
|
14353
|
-
}
|
|
14354
|
-
function emptyTokenSnapshot() {
|
|
14355
|
-
return {
|
|
14356
|
-
tokenCatalog: [],
|
|
14357
|
-
tokens: [],
|
|
14358
|
-
tokenDiagnostics: [],
|
|
14359
|
-
tokenGeneration: "empty"
|
|
14360
|
-
};
|
|
14361
|
-
}
|
|
14362
|
-
|
|
14363
|
-
// src/hosts/static/html/bootstrap.ts
|
|
14364
|
-
var CLIENT_MARKER = "data-nudge-ui-client";
|
|
14365
|
-
var MOUNT_MARKER = "data-nudge-ui-mount";
|
|
14366
|
-
function injectStandaloneBootstrap(html, options = {}) {
|
|
14367
|
-
const clientPath = options.clientPath ?? NUDGE_UI_CLIENT_PATH;
|
|
14368
|
-
const manifestPath = options.manifestPath ?? NUDGE_UI_MANIFEST_PATH;
|
|
14369
|
-
const document2 = parse(html, { sourceCodeLocationInfo: true });
|
|
14370
|
-
const sourceFacts = inspectSource(document2, clientPath);
|
|
14371
|
-
const nodes = [];
|
|
14372
|
-
if (!sourceFacts.hasMount) {
|
|
14373
|
-
nodes.push(
|
|
14374
|
-
`<div id="${NUDGE_UI_MOUNT_ID}" ${MOUNT_MARKER}></div>`
|
|
14375
|
-
);
|
|
14376
|
-
}
|
|
14377
|
-
if (!sourceFacts.hasClient) {
|
|
14378
|
-
nodes.push(
|
|
14379
|
-
`<script type="module" src="${escapeAttributeValue2(clientPath)}" ${CLIENT_MARKER} data-nudge-ui-manifest="${escapeAttributeValue2(manifestPath)}"></script>`
|
|
14380
|
-
);
|
|
14381
|
-
}
|
|
14382
|
-
if (nodes.length === 0) return { html, injected: false };
|
|
14383
|
-
const injection = `
|
|
14384
|
-
${nodes.join("\n")}
|
|
14385
|
-
`;
|
|
14386
|
-
const offset = sourceFacts.bodyEndOffset ?? sourceFacts.htmlEndOffset ?? html.length;
|
|
14387
|
-
return {
|
|
14388
|
-
html: `${html.slice(0, offset)}${injection}${html.slice(offset)}`,
|
|
14389
|
-
injected: true
|
|
14390
|
-
};
|
|
14391
|
-
}
|
|
14392
|
-
function inspectSource(document2, clientPath) {
|
|
14393
|
-
const facts = {
|
|
14394
|
-
hasMount: false,
|
|
14395
|
-
hasClient: false,
|
|
14396
|
-
bodyEndOffset: null,
|
|
14397
|
-
htmlEndOffset: null
|
|
14398
|
-
};
|
|
14399
|
-
let body = null;
|
|
14400
|
-
visitElements(document2, (element) => {
|
|
14401
|
-
if (element.namespaceURI !== "http://www.w3.org/1999/xhtml") return;
|
|
14402
|
-
const tagName = element.tagName.toLowerCase();
|
|
14403
|
-
if (tagName === "body") body = element;
|
|
14404
|
-
if (tagName === "script" && (attributeValue(element, CLIENT_MARKER) !== null || attributeValue(element, "src") === clientPath)) {
|
|
14405
|
-
facts.hasClient = true;
|
|
14406
|
-
}
|
|
14407
|
-
const endOffset = element.sourceCodeLocation?.endTag?.startOffset;
|
|
14408
|
-
if (tagName === "body" && endOffset !== void 0) facts.bodyEndOffset = endOffset;
|
|
14409
|
-
if (tagName === "html" && endOffset !== void 0) facts.htmlEndOffset = endOffset;
|
|
14410
|
-
});
|
|
14411
|
-
if (body) {
|
|
14412
|
-
visitElements(body, (element) => {
|
|
14413
|
-
if (element !== body && attributeValue(element, "id") === NUDGE_UI_MOUNT_ID) {
|
|
14414
|
-
facts.hasMount = true;
|
|
14415
|
-
}
|
|
14416
|
-
});
|
|
14417
|
-
}
|
|
14418
|
-
return facts;
|
|
14419
|
-
}
|
|
14420
|
-
function visitElements(parent, visit) {
|
|
14421
|
-
for (const child of parent.childNodes) {
|
|
14422
|
-
if (!("tagName" in child) || typeof child.tagName !== "string") continue;
|
|
14423
|
-
if (child.tagName.toLowerCase() === "template") continue;
|
|
14424
|
-
visit(child);
|
|
14425
|
-
visitElements(child, visit);
|
|
14426
|
-
}
|
|
14427
|
-
}
|
|
14428
|
-
function attributeValue(element, name) {
|
|
14429
|
-
return element.attrs.find((attribute) => attribute.name === name)?.value ?? null;
|
|
14430
|
-
}
|
|
14431
|
-
function escapeAttributeValue2(value) {
|
|
14432
|
-
return value.replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<").replaceAll(">", ">");
|
|
14433
|
-
}
|
|
14434
|
-
|
|
14435
14681
|
// src/hosts/projectBridge.ts
|
|
14436
14682
|
import { existsSync as existsSync2 } from "node:fs";
|
|
14437
14683
|
import { createRequire as createRequire2 } from "node:module";
|
|
14438
|
-
import { dirname as dirname2, join as
|
|
14684
|
+
import { dirname as dirname2, join as join3, parse as parse2 } from "node:path";
|
|
14439
14685
|
import { pathToFileURL } from "node:url";
|
|
14440
14686
|
var runningBridges = /* @__PURE__ */ new Map();
|
|
14441
14687
|
async function startOptionalProjectBridge(input) {
|
|
@@ -14456,7 +14702,7 @@ async function launchOptionalProjectBridge(input, key) {
|
|
|
14456
14702
|
runningBridges.delete(key);
|
|
14457
14703
|
return null;
|
|
14458
14704
|
}
|
|
14459
|
-
modulePath = createRequire2(
|
|
14705
|
+
modulePath = createRequire2(join3(input.appRoot, "package.json")).resolve("@nudge-ui/mcp/project");
|
|
14460
14706
|
} catch {
|
|
14461
14707
|
runningBridges.delete(key);
|
|
14462
14708
|
return null;
|
|
@@ -14498,24 +14744,24 @@ function isPnpRuntime() {
|
|
|
14498
14744
|
return typeof process.versions.pnp === "string";
|
|
14499
14745
|
}
|
|
14500
14746
|
function hasProjectInstalledMcp(appRoot) {
|
|
14501
|
-
let
|
|
14502
|
-
const root2 = parse2(
|
|
14747
|
+
let directory2 = appRoot;
|
|
14748
|
+
const root2 = parse2(directory2).root;
|
|
14503
14749
|
for (; ; ) {
|
|
14504
|
-
if (existsSync2(
|
|
14505
|
-
if (
|
|
14506
|
-
|
|
14750
|
+
if (existsSync2(join3(directory2, "node_modules", "@nudge-ui", "mcp", "package.json"))) return true;
|
|
14751
|
+
if (directory2 === root2) return false;
|
|
14752
|
+
directory2 = dirname2(directory2);
|
|
14507
14753
|
}
|
|
14508
14754
|
}
|
|
14509
14755
|
|
|
14510
14756
|
// src/project/tokens.ts
|
|
14511
|
-
import { createHash } from "node:crypto";
|
|
14757
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
14512
14758
|
import {
|
|
14513
14759
|
readFile as readUtf8File,
|
|
14514
14760
|
readdir,
|
|
14515
|
-
realpath,
|
|
14761
|
+
realpath as realpath2,
|
|
14516
14762
|
stat
|
|
14517
14763
|
} from "node:fs/promises";
|
|
14518
|
-
import { extname, isAbsolute, join as
|
|
14764
|
+
import { extname, isAbsolute as isAbsolute2, join as join4, relative as relative2, resolve, sep as sep2 } from "node:path";
|
|
14519
14765
|
|
|
14520
14766
|
// ../../node_modules/.pnpm/postcss@8.5.26/node_modules/postcss/lib/postcss.mjs
|
|
14521
14767
|
var import_postcss = __toESM(require_postcss(), 1);
|
|
@@ -15029,7 +15275,7 @@ var EMPTY_PROJECT_TOKEN_SNAPSHOT = {
|
|
|
15029
15275
|
async function createProjectTokenSnapshot(options) {
|
|
15030
15276
|
const rootDirectory = await canonicalRoot(options.rootDirectory);
|
|
15031
15277
|
const additionalRoots = (await Promise.all(
|
|
15032
|
-
(options.additionalRootDirectories ?? []).map((
|
|
15278
|
+
(options.additionalRootDirectories ?? []).map((directory2) => canonicalOptionalRoot(directory2))
|
|
15033
15279
|
)).filter((root2) => root2 !== null);
|
|
15034
15280
|
const scanRoots = [rootDirectory, ...additionalRoots.filter((root2) => root2 !== rootDirectory)];
|
|
15035
15281
|
const discovered = await Promise.all(
|
|
@@ -15039,12 +15285,12 @@ async function createProjectTokenSnapshot(options) {
|
|
|
15039
15285
|
const seenFiles = /* @__PURE__ */ new Set();
|
|
15040
15286
|
for (let index = 0; index < discovered.length; index += 1) {
|
|
15041
15287
|
for (const artifact of discovered[index] ?? []) {
|
|
15042
|
-
const canonicalPath = await
|
|
15288
|
+
const canonicalPath = await realpath2(artifact.absolutePath).catch(() => artifact.absolutePath);
|
|
15043
15289
|
if (seenFiles.has(canonicalPath)) continue;
|
|
15044
15290
|
seenFiles.add(canonicalPath);
|
|
15045
15291
|
artifacts.push({
|
|
15046
15292
|
...artifact,
|
|
15047
|
-
projectPath: index === 0 ? artifact.projectPath :
|
|
15293
|
+
projectPath: index === 0 ? artifact.projectPath : relative2(rootDirectory, artifact.absolutePath).split(sep2).join("/")
|
|
15048
15294
|
});
|
|
15049
15295
|
}
|
|
15050
15296
|
}
|
|
@@ -15087,32 +15333,32 @@ async function createProjectTokenSnapshot(options) {
|
|
|
15087
15333
|
tokenGeneration
|
|
15088
15334
|
};
|
|
15089
15335
|
}
|
|
15090
|
-
async function discoverProjectCssArtifacts(rootDirectory,
|
|
15336
|
+
async function discoverProjectCssArtifacts(rootDirectory, readFile2 = (absolutePath) => readUtf8File(absolutePath, "utf8")) {
|
|
15091
15337
|
const root2 = await canonicalRoot(rootDirectory);
|
|
15092
15338
|
const artifacts = [];
|
|
15093
15339
|
const visitedDirectories = /* @__PURE__ */ new Set();
|
|
15094
15340
|
const visitedFiles = /* @__PURE__ */ new Set();
|
|
15095
|
-
await walkDirectory(root2, root2, visitedDirectories, visitedFiles, artifacts,
|
|
15341
|
+
await walkDirectory(root2, root2, visitedDirectories, visitedFiles, artifacts, readFile2);
|
|
15096
15342
|
artifacts.sort((a, b) => comparePosixStrings(a.projectPath, b.projectPath));
|
|
15097
15343
|
return artifacts;
|
|
15098
15344
|
}
|
|
15099
|
-
async function walkDirectory(rootDirectory,
|
|
15100
|
-
const canonicalDirectoryPath = await canonicalWithinRoot(rootDirectory,
|
|
15345
|
+
async function walkDirectory(rootDirectory, directory2, visitedDirectories, visitedFiles, artifacts, readFile2) {
|
|
15346
|
+
const canonicalDirectoryPath = await canonicalWithinRoot(rootDirectory, directory2);
|
|
15101
15347
|
if (!canonicalDirectoryPath || visitedDirectories.has(canonicalDirectoryPath)) return;
|
|
15102
|
-
const projectDirectoryPath =
|
|
15103
|
-
const canonicalProjectDirectoryPath =
|
|
15348
|
+
const projectDirectoryPath = relative2(rootDirectory, directory2).split(sep2).join("/");
|
|
15349
|
+
const canonicalProjectDirectoryPath = relative2(rootDirectory, canonicalDirectoryPath).split(sep2).join("/");
|
|
15104
15350
|
if (isSensitiveProjectPath(projectDirectoryPath) || isSensitiveProjectPath(canonicalProjectDirectoryPath)) return;
|
|
15105
15351
|
visitedDirectories.add(canonicalDirectoryPath);
|
|
15106
15352
|
let entries;
|
|
15107
15353
|
try {
|
|
15108
|
-
entries = await readdir(
|
|
15354
|
+
entries = await readdir(directory2, { withFileTypes: true });
|
|
15109
15355
|
} catch {
|
|
15110
15356
|
return;
|
|
15111
15357
|
}
|
|
15112
15358
|
entries.sort((a, b) => comparePosixStrings(a.name, b.name));
|
|
15113
15359
|
for (const entry of entries) {
|
|
15114
15360
|
if (entry.isDirectory() && isExcludedDirectoryName(entry.name)) continue;
|
|
15115
|
-
const absolutePath =
|
|
15361
|
+
const absolutePath = join4(directory2, entry.name);
|
|
15116
15362
|
const canonicalPath = await canonicalWithinRoot(rootDirectory, absolutePath);
|
|
15117
15363
|
if (!canonicalPath) continue;
|
|
15118
15364
|
let stats;
|
|
@@ -15129,20 +15375,20 @@ async function walkDirectory(rootDirectory, directory, visitedDirectories, visit
|
|
|
15129
15375
|
visitedDirectories,
|
|
15130
15376
|
visitedFiles,
|
|
15131
15377
|
artifacts,
|
|
15132
|
-
|
|
15378
|
+
readFile2
|
|
15133
15379
|
);
|
|
15134
15380
|
continue;
|
|
15135
15381
|
}
|
|
15136
15382
|
if (!stats.isFile() || extname(entry.name).toLowerCase() !== ".css") continue;
|
|
15137
15383
|
if (visitedFiles.has(canonicalPath)) continue;
|
|
15138
15384
|
visitedFiles.add(canonicalPath);
|
|
15139
|
-
const projectPath =
|
|
15140
|
-
const canonicalProjectPath2 =
|
|
15385
|
+
const projectPath = relative2(rootDirectory, absolutePath).split(sep2).join("/");
|
|
15386
|
+
const canonicalProjectPath2 = relative2(rootDirectory, canonicalPath).split(sep2).join("/");
|
|
15141
15387
|
if (isSensitiveProjectPath(projectPath) || isSensitiveProjectPath(canonicalProjectPath2)) {
|
|
15142
15388
|
continue;
|
|
15143
15389
|
}
|
|
15144
15390
|
try {
|
|
15145
|
-
const content = await
|
|
15391
|
+
const content = await readFile2(absolutePath);
|
|
15146
15392
|
artifacts.push({ absolutePath, projectPath, content });
|
|
15147
15393
|
} catch (error) {
|
|
15148
15394
|
artifacts.push({
|
|
@@ -15154,7 +15400,7 @@ async function walkDirectory(rootDirectory, directory, visitedDirectories, visit
|
|
|
15154
15400
|
}
|
|
15155
15401
|
}
|
|
15156
15402
|
async function canonicalRoot(rootDirectory) {
|
|
15157
|
-
const root2 = await
|
|
15403
|
+
const root2 = await realpath2(resolve(rootDirectory));
|
|
15158
15404
|
if (!(await stat(root2)).isDirectory()) {
|
|
15159
15405
|
throw new Error(`Standalone root is not a directory: ${rootDirectory}`);
|
|
15160
15406
|
}
|
|
@@ -15169,9 +15415,9 @@ async function canonicalOptionalRoot(rootDirectory) {
|
|
|
15169
15415
|
}
|
|
15170
15416
|
async function canonicalWithinRoot(rootDirectory, candidate) {
|
|
15171
15417
|
try {
|
|
15172
|
-
const canonical = await
|
|
15173
|
-
const pathFromRoot =
|
|
15174
|
-
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)) {
|
|
15175
15421
|
return canonical;
|
|
15176
15422
|
}
|
|
15177
15423
|
} catch {
|
|
@@ -15199,7 +15445,7 @@ function deterministicGeneration(artifacts, inventoryGeneration, label) {
|
|
|
15199
15445
|
content: artifact.content,
|
|
15200
15446
|
readError: artifact.readError
|
|
15201
15447
|
}));
|
|
15202
|
-
const digest =
|
|
15448
|
+
const digest = createHash2("sha256").update(`${facts.join("\n")}
|
|
15203
15449
|
${inventoryGeneration}`).digest("hex").slice(0, 24);
|
|
15204
15450
|
return `${label}:${digest}`;
|
|
15205
15451
|
}
|
|
@@ -15211,7 +15457,7 @@ function comparePosixStrings(a, b) {
|
|
|
15211
15457
|
import { watch } from "node:fs";
|
|
15212
15458
|
import { readdir as readdir2 } from "node:fs/promises";
|
|
15213
15459
|
import { realpathSync, statSync } from "node:fs";
|
|
15214
|
-
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";
|
|
15215
15461
|
function createProjectFileWatcher(options) {
|
|
15216
15462
|
const rootDirectory = realpathSync(resolve2(options.rootDirectory));
|
|
15217
15463
|
const debounceMs = Math.max(0, options.debounceMs ?? 60);
|
|
@@ -15241,30 +15487,30 @@ function createProjectFileWatcher(options) {
|
|
|
15241
15487
|
pending.clear();
|
|
15242
15488
|
void Promise.resolve(options.onSettled(changes)).catch(reportError);
|
|
15243
15489
|
};
|
|
15244
|
-
const closeDirectory = (
|
|
15245
|
-
const entry = watches.get(
|
|
15490
|
+
const closeDirectory = (directory2) => {
|
|
15491
|
+
const entry = watches.get(directory2);
|
|
15246
15492
|
if (!entry) return;
|
|
15247
|
-
watches.delete(
|
|
15493
|
+
watches.delete(directory2);
|
|
15248
15494
|
entry.watcher.close();
|
|
15249
15495
|
};
|
|
15250
|
-
const closeDescendants = (
|
|
15496
|
+
const closeDescendants = (directory2) => {
|
|
15251
15497
|
for (const watchedDirectory of [...watches.keys()]) {
|
|
15252
|
-
if (watchedDirectory ===
|
|
15498
|
+
if (watchedDirectory === directory2 || watchedDirectory.startsWith(`${directory2}${sep3}`)) {
|
|
15253
15499
|
closeDirectory(watchedDirectory);
|
|
15254
15500
|
}
|
|
15255
15501
|
}
|
|
15256
15502
|
};
|
|
15257
|
-
const watchDirectory = (
|
|
15258
|
-
if (closed || !isProjectDirectory(rootDirectory,
|
|
15259
|
-
const canonicalDirectory2 = canonicalProjectPath(rootDirectory,
|
|
15503
|
+
const watchDirectory = (directory2) => {
|
|
15504
|
+
if (closed || !isProjectDirectory(rootDirectory, directory2)) return;
|
|
15505
|
+
const canonicalDirectory2 = canonicalProjectPath(rootDirectory, directory2);
|
|
15260
15506
|
if (!canonicalDirectory2 || [...watches.values()].some(
|
|
15261
15507
|
(entry) => entry.canonicalDirectory === canonicalDirectory2
|
|
15262
15508
|
)) return;
|
|
15263
15509
|
let directoryWatcher;
|
|
15264
15510
|
try {
|
|
15265
|
-
directoryWatcher = watch(
|
|
15511
|
+
directoryWatcher = watch(directory2, { persistent: true }, (eventType, filename) => {
|
|
15266
15512
|
const changedName = filename?.toString();
|
|
15267
|
-
const changedPath = changedName ?
|
|
15513
|
+
const changedPath = changedName ? join5(directory2, changedName) : directory2;
|
|
15268
15514
|
if (!isProjectPath(rootDirectory, changedPath)) return;
|
|
15269
15515
|
if (isProjectDirectory(rootDirectory, changedPath)) watchDirectory(changedPath);
|
|
15270
15516
|
else if (!exists(changedPath)) closeDescendants(changedPath);
|
|
@@ -15275,17 +15521,17 @@ function createProjectFileWatcher(options) {
|
|
|
15275
15521
|
reportError(error);
|
|
15276
15522
|
return;
|
|
15277
15523
|
}
|
|
15278
|
-
watches.set(
|
|
15524
|
+
watches.set(directory2, { directory: directory2, canonicalDirectory: canonicalDirectory2, watcher: directoryWatcher });
|
|
15279
15525
|
pendingScans += 1;
|
|
15280
|
-
scanQueue = scanQueue.then(() => scanSubdirectories(
|
|
15526
|
+
scanQueue = scanQueue.then(() => scanSubdirectories(directory2)).catch(reportError).finally(() => {
|
|
15281
15527
|
pendingScans -= 1;
|
|
15282
15528
|
if (pendingScans === 0) resolveReady?.();
|
|
15283
15529
|
});
|
|
15284
15530
|
};
|
|
15285
|
-
const scanSubdirectories = async (
|
|
15531
|
+
const scanSubdirectories = async (directory2) => {
|
|
15286
15532
|
let entries;
|
|
15287
15533
|
try {
|
|
15288
|
-
entries = await readdir2(
|
|
15534
|
+
entries = await readdir2(directory2, { withFileTypes: true });
|
|
15289
15535
|
} catch {
|
|
15290
15536
|
return;
|
|
15291
15537
|
}
|
|
@@ -15293,7 +15539,7 @@ function createProjectFileWatcher(options) {
|
|
|
15293
15539
|
for (const entry of entries) {
|
|
15294
15540
|
if (closed) return;
|
|
15295
15541
|
if (!entry.isDirectory() || isExcludedDirectoryName(entry.name)) continue;
|
|
15296
|
-
const child =
|
|
15542
|
+
const child = join5(directory2, entry.name);
|
|
15297
15543
|
if (!isProjectPath(rootDirectory, child)) continue;
|
|
15298
15544
|
watchDirectory(child);
|
|
15299
15545
|
}
|
|
@@ -15317,7 +15563,7 @@ function createProjectFileWatcher(options) {
|
|
|
15317
15563
|
timer = null;
|
|
15318
15564
|
}
|
|
15319
15565
|
pending.clear();
|
|
15320
|
-
for (const
|
|
15566
|
+
for (const directory2 of [...watches.keys()]) closeDirectory(directory2);
|
|
15321
15567
|
await scanQueue;
|
|
15322
15568
|
}
|
|
15323
15569
|
};
|
|
@@ -15355,24 +15601,24 @@ function isProjectPath(rootDirectory, path) {
|
|
|
15355
15601
|
function canonicalProjectPath(rootDirectory, path) {
|
|
15356
15602
|
try {
|
|
15357
15603
|
const canonical = realpathSync(path);
|
|
15358
|
-
return isWithin(rootDirectory, canonical) && !isSensitiveProjectPath(
|
|
15604
|
+
return isWithin(rootDirectory, canonical) && !isSensitiveProjectPath(relative3(rootDirectory, canonical).split(sep3).join("/")) ? canonical : null;
|
|
15359
15605
|
} catch {
|
|
15360
15606
|
const parent = dirname3(path);
|
|
15361
15607
|
if (parent === path) return null;
|
|
15362
15608
|
try {
|
|
15363
15609
|
const canonicalParent = realpathSync(parent);
|
|
15364
|
-
return isWithin(rootDirectory, canonicalParent) && !isSensitiveProjectPath(
|
|
15610
|
+
return isWithin(rootDirectory, canonicalParent) && !isSensitiveProjectPath(relative3(rootDirectory, canonicalParent).split(sep3).join("/")) ? canonicalParent : null;
|
|
15365
15611
|
} catch {
|
|
15366
15612
|
return null;
|
|
15367
15613
|
}
|
|
15368
15614
|
}
|
|
15369
15615
|
}
|
|
15370
15616
|
function isExcludedDirectory(rootDirectory, path) {
|
|
15371
|
-
return
|
|
15617
|
+
return relative3(rootDirectory, resolve2(path)).split(sep3).some((segment) => isExcludedDirectoryName(segment));
|
|
15372
15618
|
}
|
|
15373
15619
|
function isWithin(rootDirectory, candidate) {
|
|
15374
|
-
const pathFromRoot =
|
|
15375
|
-
return pathFromRoot === "" || !pathFromRoot.startsWith(`..${
|
|
15620
|
+
const pathFromRoot = relative3(rootDirectory, candidate);
|
|
15621
|
+
return pathFromRoot === "" || !pathFromRoot.startsWith(`..${sep3}`) && pathFromRoot !== ".." && !isAbsolute3(pathFromRoot);
|
|
15376
15622
|
}
|
|
15377
15623
|
function comparePosixStrings2(a, b) {
|
|
15378
15624
|
return Buffer.from(a, "utf8").compare(Buffer.from(b, "utf8"));
|
|
@@ -15393,15 +15639,15 @@ function createStandaloneServer(options) {
|
|
|
15393
15639
|
validatePort(port);
|
|
15394
15640
|
const clientPath = options.clientPath;
|
|
15395
15641
|
const projectId = options.projectId ?? createStandaloneProjectId(rootDirectory);
|
|
15396
|
-
let
|
|
15642
|
+
let revision2 = 0;
|
|
15397
15643
|
let manifest = createStandaloneRuntimeManifest(
|
|
15398
15644
|
projectId,
|
|
15399
15645
|
EMPTY_PROJECT_TOKEN_SNAPSHOT,
|
|
15400
|
-
|
|
15646
|
+
revision2
|
|
15401
15647
|
);
|
|
15402
15648
|
let projectBridge = null;
|
|
15403
15649
|
const initialTokens = createProjectTokenSnapshot({ rootDirectory, generationLabel: "static-html" }).then((tokens) => {
|
|
15404
|
-
manifest = createStandaloneRuntimeManifest(projectId, tokens,
|
|
15650
|
+
manifest = createStandaloneRuntimeManifest(projectId, tokens, revision2);
|
|
15405
15651
|
return tokens;
|
|
15406
15652
|
});
|
|
15407
15653
|
void initialTokens.catch(() => void 0);
|
|
@@ -15417,7 +15663,7 @@ function createStandaloneServer(options) {
|
|
|
15417
15663
|
};
|
|
15418
15664
|
const notifyReload = () => {
|
|
15419
15665
|
const payload = `event: reload
|
|
15420
|
-
data: ${JSON.stringify({ revision })}
|
|
15666
|
+
data: ${JSON.stringify({ revision: revision2 })}
|
|
15421
15667
|
|
|
15422
15668
|
`;
|
|
15423
15669
|
for (const client of [...reloadClients]) {
|
|
@@ -15437,10 +15683,10 @@ data: ${JSON.stringify({ revision })}
|
|
|
15437
15683
|
changeQueue = changeQueue.then(async () => {
|
|
15438
15684
|
const tokens = await createProjectTokenSnapshot({ rootDirectory, generationLabel: "static-html" });
|
|
15439
15685
|
manifest = {
|
|
15440
|
-
...createStandaloneRuntimeManifest(projectId, tokens,
|
|
15686
|
+
...createStandaloneRuntimeManifest(projectId, tokens, revision2 + 1),
|
|
15441
15687
|
...projectBridge ? { agentBridge: projectBridge.browser } : {}
|
|
15442
15688
|
};
|
|
15443
|
-
|
|
15689
|
+
revision2 += 1;
|
|
15444
15690
|
notifyReload();
|
|
15445
15691
|
}).catch((error) => {
|
|
15446
15692
|
console.warn(
|
|
@@ -15575,7 +15821,7 @@ function resolveDecodedStaticFile(root2, decodedPath) {
|
|
|
15575
15821
|
let filePath = canonicalCandidate;
|
|
15576
15822
|
const stats = statSync2(filePath);
|
|
15577
15823
|
if (stats.isDirectory()) {
|
|
15578
|
-
const indexCandidate =
|
|
15824
|
+
const indexCandidate = join6(filePath, "index.html");
|
|
15579
15825
|
const canonicalIndex = canonicalExistingAncestor(indexCandidate);
|
|
15580
15826
|
if (!canonicalIndex || !isWithin2(root2, canonicalIndex) || !existsSync3(indexCandidate)) {
|
|
15581
15827
|
return null;
|
|
@@ -15585,13 +15831,13 @@ function resolveDecodedStaticFile(root2, decodedPath) {
|
|
|
15585
15831
|
} else if (!stats.isFile()) {
|
|
15586
15832
|
return null;
|
|
15587
15833
|
}
|
|
15588
|
-
const relativePath =
|
|
15834
|
+
const relativePath = relative4(root2, filePath).split("\\").join("/");
|
|
15589
15835
|
if (isSensitiveProjectPath(relativePath)) return null;
|
|
15590
15836
|
return { absolutePath: filePath, projectPath: relativePath };
|
|
15591
15837
|
}
|
|
15592
15838
|
function createStandaloneProjectId(rootDirectory) {
|
|
15593
15839
|
const canonicalRoot2 = canonicalDirectory(rootDirectory);
|
|
15594
|
-
const digest =
|
|
15840
|
+
const digest = createHash3("sha256").update(canonicalRoot2).digest("hex").slice(0, 24);
|
|
15595
15841
|
return `static-html:${digest}`;
|
|
15596
15842
|
}
|
|
15597
15843
|
function contentTypeForPath(filePath) {
|
|
@@ -15601,15 +15847,15 @@ function contentTypeForPath(filePath) {
|
|
|
15601
15847
|
function isReservedNudgeUiRoute2(pathname) {
|
|
15602
15848
|
return pathname === NUDGE_UI_ROUTE_PREFIX.slice(0, -1) || pathname.startsWith(NUDGE_UI_ROUTE_PREFIX);
|
|
15603
15849
|
}
|
|
15604
|
-
function canonicalDirectory(
|
|
15605
|
-
const canonical = canonicalDirectoryOrNull(
|
|
15606
|
-
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}`);
|
|
15607
15853
|
return canonical;
|
|
15608
15854
|
}
|
|
15609
|
-
function canonicalDirectoryOrNull(
|
|
15610
|
-
if (!
|
|
15855
|
+
function canonicalDirectoryOrNull(directory2) {
|
|
15856
|
+
if (!isAbsolute4(directory2)) return null;
|
|
15611
15857
|
try {
|
|
15612
|
-
const canonical = realpathSync2(
|
|
15858
|
+
const canonical = realpathSync2(directory2);
|
|
15613
15859
|
return statSync2(canonical).isDirectory() ? canonical : null;
|
|
15614
15860
|
} catch {
|
|
15615
15861
|
return null;
|
|
@@ -15667,11 +15913,12 @@ function isMissingPathError(error) {
|
|
|
15667
15913
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
15668
15914
|
}
|
|
15669
15915
|
function isWithin2(root2, candidate) {
|
|
15670
|
-
const pathFromRoot =
|
|
15671
|
-
return pathFromRoot === "" || !pathFromRoot.startsWith("..") && !
|
|
15916
|
+
const pathFromRoot = relative4(root2, candidate);
|
|
15917
|
+
return pathFromRoot === "" || !pathFromRoot.startsWith("..") && !isAbsolute4(pathFromRoot);
|
|
15672
15918
|
}
|
|
15673
15919
|
async function handleRequest(input) {
|
|
15674
15920
|
const { request, response } = input;
|
|
15921
|
+
if (await handleHtmlArtifactRequest(request, response, input.rootDirectory)) return;
|
|
15675
15922
|
if (request.method !== "GET" && request.method !== "HEAD") {
|
|
15676
15923
|
sendText(response, 405, "Method Not Allowed", { Allow: "GET, HEAD" });
|
|
15677
15924
|
return;
|
|
@@ -15686,8 +15933,8 @@ async function handleRequest(input) {
|
|
|
15686
15933
|
return;
|
|
15687
15934
|
}
|
|
15688
15935
|
if (isNudgeUiEditorDocumentRequest(request.url ?? "/", request.method, request.headers)) {
|
|
15689
|
-
const
|
|
15690
|
-
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" });
|
|
15691
15938
|
return;
|
|
15692
15939
|
}
|
|
15693
15940
|
const resolution = resolveDecodedStaticFile(input.rootDirectory, decodedPath);
|
|
@@ -15698,7 +15945,7 @@ async function handleRequest(input) {
|
|
|
15698
15945
|
const isHtml = HTML_EXTENSIONS.has(extname2(resolution.projectPath).toLowerCase());
|
|
15699
15946
|
const contentType = contentTypeForPath(resolution.projectPath);
|
|
15700
15947
|
if (request.method === "HEAD") {
|
|
15701
|
-
const
|
|
15948
|
+
const body3 = await readProjectFile(resolution.absolutePath);
|
|
15702
15949
|
if (isHtml) {
|
|
15703
15950
|
response.writeHead(200, {
|
|
15704
15951
|
"Content-Type": contentType,
|
|
@@ -15707,25 +15954,25 @@ async function handleRequest(input) {
|
|
|
15707
15954
|
});
|
|
15708
15955
|
response.end();
|
|
15709
15956
|
} else {
|
|
15710
|
-
sendBody(response, 200,
|
|
15957
|
+
sendBody(response, 200, body3, contentType);
|
|
15711
15958
|
}
|
|
15712
15959
|
return;
|
|
15713
15960
|
}
|
|
15714
|
-
let
|
|
15961
|
+
let body2 = await readProjectFile(resolution.absolutePath);
|
|
15715
15962
|
if (isHtml) {
|
|
15716
|
-
|
|
15963
|
+
body2 = instrumentHtmlResponse(body2, resolution.projectPath);
|
|
15717
15964
|
}
|
|
15718
|
-
sendBody(response, 200,
|
|
15965
|
+
sendBody(response, 200, body2, contentType, isHtml ? { "Cache-Control": "no-cache" } : {});
|
|
15719
15966
|
}
|
|
15720
|
-
function instrumentHtmlResponse(
|
|
15967
|
+
function instrumentHtmlResponse(body2, projectPath) {
|
|
15721
15968
|
let source;
|
|
15722
15969
|
try {
|
|
15723
|
-
source = strictUtf8Decoder.decode(
|
|
15970
|
+
source = strictUtf8Decoder.decode(body2);
|
|
15724
15971
|
} catch {
|
|
15725
15972
|
console.warn(
|
|
15726
15973
|
`Nudge UI served ${projectPath} without instrumentation because it is not valid UTF-8.`
|
|
15727
15974
|
);
|
|
15728
|
-
return
|
|
15975
|
+
return body2;
|
|
15729
15976
|
}
|
|
15730
15977
|
const identified = instrumentSourceHtml(source, projectPath);
|
|
15731
15978
|
const bootstrapped = injectStandaloneBootstrap(identified.html);
|
|
@@ -15734,23 +15981,23 @@ function instrumentHtmlResponse(body, projectPath) {
|
|
|
15734
15981
|
var strictUtf8Decoder = new TextDecoder("utf-8", { fatal: true });
|
|
15735
15982
|
async function handleNudgeUiRoute(input, pathname) {
|
|
15736
15983
|
if (pathname === NUDGE_UI_MANIFEST_PATH) {
|
|
15737
|
-
const
|
|
15738
|
-
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", {
|
|
15739
15986
|
"Cache-Control": "no-store"
|
|
15740
15987
|
});
|
|
15741
15988
|
return;
|
|
15742
15989
|
}
|
|
15743
15990
|
if (pathname === NUDGE_UI_EDITOR_PATH) {
|
|
15744
|
-
const
|
|
15745
|
-
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", {
|
|
15746
15993
|
"Cache-Control": "no-store"
|
|
15747
15994
|
});
|
|
15748
15995
|
return;
|
|
15749
15996
|
}
|
|
15750
15997
|
if (pathname === NUDGE_UI_CLIENT_PATH) {
|
|
15751
15998
|
try {
|
|
15752
|
-
const
|
|
15753
|
-
sendBody(input.response, 200,
|
|
15999
|
+
const body2 = await readFileFromDescriptor(input.clientPath ?? resolveDefaultClientPath());
|
|
16000
|
+
sendBody(input.response, 200, body2, "text/javascript; charset=utf-8", {
|
|
15754
16001
|
"Cache-Control": "no-cache"
|
|
15755
16002
|
});
|
|
15756
16003
|
} catch {
|
|
@@ -15827,14 +16074,14 @@ function validatePort(port) {
|
|
|
15827
16074
|
function sendText(response, status, text, headers = {}) {
|
|
15828
16075
|
sendBody(response, status, Buffer.from(text, "utf8"), "text/plain; charset=utf-8", headers);
|
|
15829
16076
|
}
|
|
15830
|
-
function sendBody(response, status,
|
|
16077
|
+
function sendBody(response, status, body2, contentType, headers = {}) {
|
|
15831
16078
|
response.writeHead(status, {
|
|
15832
16079
|
"Content-Type": contentType,
|
|
15833
|
-
"Content-Length":
|
|
16080
|
+
"Content-Length": body2.byteLength,
|
|
15834
16081
|
"X-Content-Type-Options": "nosniff",
|
|
15835
16082
|
...headers
|
|
15836
16083
|
});
|
|
15837
|
-
if (response.req?.method !== "HEAD") response.end(
|
|
16084
|
+
if (response.req?.method !== "HEAD") response.end(body2);
|
|
15838
16085
|
else response.end();
|
|
15839
16086
|
}
|
|
15840
16087
|
var MIME_TYPES2 = {
|
|
@@ -15870,7 +16117,7 @@ function parseServeArguments(args, currentDirectory = process.cwd()) {
|
|
|
15870
16117
|
if (args[0] !== "serve") {
|
|
15871
16118
|
throw new Error("Usage: nudge-ui serve [directory] [--port <port>] [--host <loopback>]");
|
|
15872
16119
|
}
|
|
15873
|
-
let
|
|
16120
|
+
let directory2 = ".";
|
|
15874
16121
|
let host = "127.0.0.1";
|
|
15875
16122
|
let port = 4173;
|
|
15876
16123
|
let directoryProvided = false;
|
|
@@ -15887,13 +16134,13 @@ function parseServeArguments(args, currentDirectory = process.cwd()) {
|
|
|
15887
16134
|
} else if (argument.startsWith("-")) {
|
|
15888
16135
|
throw new Error(`Unknown option: ${argument}`);
|
|
15889
16136
|
} else if (!directoryProvided) {
|
|
15890
|
-
|
|
16137
|
+
directory2 = argument;
|
|
15891
16138
|
directoryProvided = true;
|
|
15892
16139
|
} else {
|
|
15893
16140
|
throw new Error(`Unexpected argument: ${argument}`);
|
|
15894
16141
|
}
|
|
15895
16142
|
}
|
|
15896
|
-
return { rootDirectory: resolve4(currentDirectory,
|
|
16143
|
+
return { rootDirectory: resolve4(currentDirectory, directory2), host, port };
|
|
15897
16144
|
}
|
|
15898
16145
|
async function runServeCommand(options) {
|
|
15899
16146
|
const server = createStandaloneServer(options);
|