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
|
@@ -78,6 +78,10 @@ export declare function interpretColorValue(value: string, ctx: ColorSemanticsCo
|
|
|
78
78
|
* unparseable opacities return an explicit `ok: false`.
|
|
79
79
|
*/
|
|
80
80
|
export declare function applyColorOpacity(value: string, opacity: string): ColorEditResult;
|
|
81
|
+
/** Applies opacity using RGB channels for hex colors so field edits retain percentage precision. */
|
|
82
|
+
export declare function withColorOpacity(color: string, opacity: string): ColorEditResult;
|
|
83
|
+
/** Preserves the previous opacity when the replacement color has no explicit alpha. */
|
|
84
|
+
export declare function replaceColorPreservingOpacity(previous: string, color: string, context: ColorSemanticsContext): ColorEditResult;
|
|
81
85
|
/**
|
|
82
86
|
* Replaces only the color token in a separable color expression. Keeping this
|
|
83
87
|
* separate from a plain token swap preserves authored alpha modifiers, for
|
|
@@ -398,6 +398,23 @@ export function applyColorOpacity(value, opacity) {
|
|
|
398
398
|
}
|
|
399
399
|
return { ok: false, reason: "unsupported" };
|
|
400
400
|
}
|
|
401
|
+
/** Applies opacity using RGB channels for hex colors so field edits retain percentage precision. */
|
|
402
|
+
export function withColorOpacity(color, opacity) {
|
|
403
|
+
const hex = /^#([\da-f]{3}|[\da-f]{4}|[\da-f]{6}|[\da-f]{8})$/i.exec(color.trim());
|
|
404
|
+
if (hex) {
|
|
405
|
+
const raw = hex[1];
|
|
406
|
+
const channels = rgbTuple(`#${raw.slice(0, raw.length <= 4 ? 3 : 6)}`);
|
|
407
|
+
color = `rgb(${channels.join(" ")} / 100%)`;
|
|
408
|
+
}
|
|
409
|
+
return applyColorOpacity(color, opacity);
|
|
410
|
+
}
|
|
411
|
+
/** Preserves the previous opacity when the replacement color has no explicit alpha. */
|
|
412
|
+
export function replaceColorPreservingOpacity(previous, color, context) {
|
|
413
|
+
const opacity = interpretColorOpacity(previous, context);
|
|
414
|
+
return opacity && !colorValueHasEmbeddedAlpha(color)
|
|
415
|
+
? withColorOpacity(color, opacity.value)
|
|
416
|
+
: { ok: true, value: color };
|
|
417
|
+
}
|
|
401
418
|
function tokenReferenceName(entry) {
|
|
402
419
|
const name = entry.cssName ?? entry.name;
|
|
403
420
|
return name.startsWith("--") ? name : null;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { handleHtmlArtifactRequest } from "../../project/artifacts.js";
|
|
1
2
|
import {} from "../../inspector/clientManifest.js";
|
|
2
3
|
import { createAstroRuntimeConfig } from "./astroRuntimeConfig.js";
|
|
3
4
|
import { createAstroClientAssetHandler } from "./clientAsset.js";
|
|
4
5
|
import { NUDGE_UI_CLIENT_PATH, NUDGE_UI_EDITOR_PATH, NUDGE_UI_MANIFEST_PATH, createNudgeUiEditorDocument, isNudgeUiEditorDocumentRequest, } from "../../transport/index.js";
|
|
5
6
|
import { startOptionalProjectBridge } from "../projectBridge.js";
|
|
7
|
+
import { automationManifestFields } from "../environment.js";
|
|
6
8
|
const serveClient = createAstroClientAssetHandler();
|
|
7
9
|
/** Serves the prebuilt client and its host-neutral manifest in Astro dev. */
|
|
8
10
|
export function createAstroClientTransportPlugin() {
|
|
@@ -16,38 +18,9 @@ export function createAstroClientTransportPlugin() {
|
|
|
16
18
|
apply: "serve",
|
|
17
19
|
configureServer(server) {
|
|
18
20
|
server.middlewares.use((request, response, next) => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
response.statusCode = 405;
|
|
23
|
-
response.setHeader("Allow", "GET, HEAD");
|
|
24
|
-
response.end();
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
response.statusCode = 200;
|
|
28
|
-
response.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
29
|
-
response.setHeader("Cache-Control", "no-store");
|
|
30
|
-
response.end(request.method === "HEAD" ? undefined : createNudgeUiEditorDocument());
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
if (pathname === NUDGE_UI_CLIENT_PATH) {
|
|
34
|
-
void serveClient(request, response).catch(next);
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
if (pathname === NUDGE_UI_MANIFEST_PATH) {
|
|
38
|
-
void createManifest(server, request, (bridge) => {
|
|
39
|
-
projectBridge = bridge;
|
|
40
|
-
})
|
|
41
|
-
.then((manifest) => {
|
|
42
|
-
response.statusCode = 200;
|
|
43
|
-
response.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
44
|
-
response.setHeader("Cache-Control", "no-store");
|
|
45
|
-
response.end(JSON.stringify(manifest));
|
|
46
|
-
})
|
|
47
|
-
.catch(next);
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
next();
|
|
21
|
+
void handleHtmlArtifactRequest(request, response, server.config.root)
|
|
22
|
+
.then((handled) => { if (!handled)
|
|
23
|
+
handleClientRequest(server, request, response, next); }).catch(next);
|
|
51
24
|
});
|
|
52
25
|
},
|
|
53
26
|
async closeBundle() {
|
|
@@ -55,6 +28,40 @@ export function createAstroClientTransportPlugin() {
|
|
|
55
28
|
projectBridge = null;
|
|
56
29
|
},
|
|
57
30
|
};
|
|
31
|
+
function handleClientRequest(server, request, response, next) {
|
|
32
|
+
const pathname = new URL(request.url ?? "/", "http://nudge-ui.local").pathname;
|
|
33
|
+
if (isNudgeUiEditorDocumentRequest(request.url ?? "/", request.method, request.headers)) {
|
|
34
|
+
if (request.method !== "GET" && request.method !== "HEAD") {
|
|
35
|
+
response.statusCode = 405;
|
|
36
|
+
response.setHeader("Allow", "GET, HEAD");
|
|
37
|
+
response.end();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
response.statusCode = 200;
|
|
41
|
+
response.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
42
|
+
response.setHeader("Cache-Control", "no-store");
|
|
43
|
+
response.end(request.method === "HEAD" ? undefined : createNudgeUiEditorDocument());
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (pathname === NUDGE_UI_CLIENT_PATH) {
|
|
47
|
+
void serveClient(request, response).catch(next);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (pathname === NUDGE_UI_MANIFEST_PATH) {
|
|
51
|
+
void createManifest(server, request, (bridge) => {
|
|
52
|
+
projectBridge = bridge;
|
|
53
|
+
})
|
|
54
|
+
.then((manifest) => {
|
|
55
|
+
response.statusCode = 200;
|
|
56
|
+
response.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
57
|
+
response.setHeader("Cache-Control", "no-store");
|
|
58
|
+
response.end(JSON.stringify(manifest));
|
|
59
|
+
})
|
|
60
|
+
.catch(next);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
next();
|
|
64
|
+
}
|
|
58
65
|
}
|
|
59
66
|
async function createManifest(server, request, setBridge) {
|
|
60
67
|
// SAFETY: these virtual modules are generated by the shared Nudge UI plugin
|
|
@@ -77,6 +84,7 @@ async function createManifest(server, request, setBridge) {
|
|
|
77
84
|
appRoot: server.config.root,
|
|
78
85
|
projectId: runtime.projectId,
|
|
79
86
|
origin,
|
|
87
|
+
info: (message) => server.config.logger.info(message),
|
|
80
88
|
warn: (message) => server.config.logger.warn(message),
|
|
81
89
|
})
|
|
82
90
|
: null;
|
|
@@ -86,6 +94,7 @@ async function createManifest(server, request, setBridge) {
|
|
|
86
94
|
revision: 0,
|
|
87
95
|
runtime,
|
|
88
96
|
...(bridge ? { agentBridge: bridge.browser } : {}),
|
|
97
|
+
...automationManifestFields(),
|
|
89
98
|
};
|
|
90
99
|
}
|
|
91
100
|
function resolvedRequestOrigin(server, request) {
|
|
@@ -11,8 +11,8 @@ export interface NudgeUiAstroOptions extends NudgeUiOptions {
|
|
|
11
11
|
/**
|
|
12
12
|
* Nudge UI host Adapter for Astro dev servers (ADR-0011).
|
|
13
13
|
*
|
|
14
|
-
* Dev-only by contract (ADR-0002): unless `command === "dev"
|
|
15
|
-
* `enabled !== false`, the integration registers nothing at all — no Vite
|
|
14
|
+
* Dev-only by contract (ADR-0002): unless `command === "dev"`,
|
|
15
|
+
* `enabled !== false`, and `NUDGE_UI` is not `0`, the integration registers nothing at all — no Vite
|
|
16
16
|
* plugins, no injected scripts, no middleware — so `astro build` output is
|
|
17
17
|
* byte-identical to a project without the integration.
|
|
18
18
|
*
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
1
2
|
import { nudgeUi } from "../vite/index.js";
|
|
2
3
|
import { NUDGE_UI_CLIENT_PATH, NUDGE_UI_MANIFEST_PATH } from "../../transport/index.js";
|
|
3
4
|
import { createAstroClientTransportPlugin, } from "./clientTransport.js";
|
|
4
5
|
import { createProjectContextPlugin } from "./projectContext.js";
|
|
6
|
+
import { isNudgeUiEnabled } from "../environment.js";
|
|
7
|
+
import { installMarkdownIdentity } from "./markdownIdentity.js";
|
|
5
8
|
/**
|
|
6
9
|
* Adds the prebuilt client as an external module. The inspector dependency
|
|
7
10
|
* graph therefore never enters Astro's Vite optimizer.
|
|
@@ -23,8 +26,8 @@ const MIDDLEWARE_ENTRYPOINT = new URL(import.meta.url.endsWith(".ts") ? "./middl
|
|
|
23
26
|
/**
|
|
24
27
|
* Nudge UI host Adapter for Astro dev servers (ADR-0011).
|
|
25
28
|
*
|
|
26
|
-
* Dev-only by contract (ADR-0002): unless `command === "dev"
|
|
27
|
-
* `enabled !== false`, the integration registers nothing at all — no Vite
|
|
29
|
+
* Dev-only by contract (ADR-0002): unless `command === "dev"`,
|
|
30
|
+
* `enabled !== false`, and `NUDGE_UI` is not `0`, the integration registers nothing at all — no Vite
|
|
28
31
|
* plugins, no injected scripts, no middleware — so `astro build` output is
|
|
29
32
|
* byte-identical to a project without the integration.
|
|
30
33
|
*
|
|
@@ -37,19 +40,21 @@ const MIDDLEWARE_ENTRYPOINT = new URL(import.meta.url.endsWith(".ts") ? "./middl
|
|
|
37
40
|
* identity Module.
|
|
38
41
|
*/
|
|
39
42
|
export function nudgeUiAstro(options = {}) {
|
|
40
|
-
const enabled = options.enabled
|
|
43
|
+
const enabled = isNudgeUiEnabled(options.enabled);
|
|
41
44
|
const sharedOptions = { ...options };
|
|
42
45
|
return {
|
|
43
46
|
name: "nudge-ui",
|
|
44
47
|
hooks: {
|
|
45
|
-
"astro:config:setup"({ command, updateConfig, injectScript, addMiddleware }) {
|
|
48
|
+
"astro:config:setup"({ command, config, updateConfig, injectScript, addMiddleware }) {
|
|
46
49
|
if (!enabled || command !== "dev")
|
|
47
50
|
return;
|
|
51
|
+
const markdown = installMarkdownIdentity(config.markdown, fileURLToPath(config.root));
|
|
48
52
|
// The shared plugin objects are plain Vite plugin records, but this
|
|
49
53
|
// monorepo typechecks them against a different Vite major than the
|
|
50
54
|
// installed Astro resolves internally; the runtime contract
|
|
51
55
|
// (config/resolveId/load/transform hooks) is identical.
|
|
52
56
|
updateConfig({
|
|
57
|
+
...(markdown ? { markdown } : {}),
|
|
53
58
|
vite: {
|
|
54
59
|
// SAFETY: Astro and this package resolve different Vite type
|
|
55
60
|
// versions, but both consume the same runtime Plugin contract.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Element, Root } from "hast";
|
|
2
|
+
/** Adds authored Markdown positions through the remark/rehype pipeline. */
|
|
3
|
+
export declare function createMarkdownIdentityPlugin(projectRoot: string): () => (tree: Root, file: {
|
|
4
|
+
path?: string;
|
|
5
|
+
}) => void;
|
|
6
|
+
/** Adds the same identity through Astro's Sätteri visitor API. */
|
|
7
|
+
export declare function createSatteriIdentityPlugin(projectRoot: string): {
|
|
8
|
+
name: string;
|
|
9
|
+
options: {
|
|
10
|
+
position: boolean;
|
|
11
|
+
};
|
|
12
|
+
element: {
|
|
13
|
+
filter: string[];
|
|
14
|
+
visit(node: Readonly<Element>, context: {
|
|
15
|
+
fileURL: URL | undefined;
|
|
16
|
+
setProperty(node: Readonly<Element>, key: string, value: string): void;
|
|
17
|
+
}): void;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
/** Extends supported processors without replacing the consumer's pipeline. */
|
|
21
|
+
export declare function installMarkdownIdentity(markdown: {
|
|
22
|
+
processor?: {
|
|
23
|
+
name: string;
|
|
24
|
+
options: object;
|
|
25
|
+
};
|
|
26
|
+
}, projectRoot: string): {
|
|
27
|
+
rehypePlugins: ReturnType<typeof createMarkdownIdentityPlugin>[];
|
|
28
|
+
} | undefined;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
const PROSE_TAGS = [
|
|
4
|
+
"p", "h1", "h2", "h3", "h4", "h5", "h6", "ul", "ol", "li",
|
|
5
|
+
"blockquote", "a", "em", "strong", "del", "code", "pre", "hr", "br",
|
|
6
|
+
"table", "thead", "tbody", "tr", "th", "td",
|
|
7
|
+
];
|
|
8
|
+
const proseTags = new Set(PROSE_TAGS);
|
|
9
|
+
function attributesFor(node, file, projectRoot) {
|
|
10
|
+
const start = node.position?.start;
|
|
11
|
+
if (!start || start.line < 1 || start.column < 1 || !proseTags.has(node.tagName))
|
|
12
|
+
return {};
|
|
13
|
+
const relative = path.relative(projectRoot, file).replaceAll("\\", "/");
|
|
14
|
+
const attributes = {};
|
|
15
|
+
const properties = node.properties;
|
|
16
|
+
if (properties["data-cid"] === undefined && properties.dataCid === undefined) {
|
|
17
|
+
attributes["data-cid"] = `astro:${node.tagName.charAt(0).toUpperCase()}${node.tagName.slice(1)}`;
|
|
18
|
+
}
|
|
19
|
+
if (properties["data-src"] === undefined && properties.dataSrc === undefined) {
|
|
20
|
+
attributes["data-src"] = `${relative}:${start.line}:${start.column}`;
|
|
21
|
+
}
|
|
22
|
+
return attributes;
|
|
23
|
+
}
|
|
24
|
+
/** Adds authored Markdown positions through the remark/rehype pipeline. */
|
|
25
|
+
export function createMarkdownIdentityPlugin(projectRoot) {
|
|
26
|
+
return function nudgeMarkdownIdentity() {
|
|
27
|
+
return (tree, file) => {
|
|
28
|
+
if (!file.path || !/\.mdx?$/.test(file.path))
|
|
29
|
+
return;
|
|
30
|
+
const sourceFile = file.path;
|
|
31
|
+
const visit = (node) => {
|
|
32
|
+
if (node.type === "element") {
|
|
33
|
+
Object.assign(node.properties, attributesFor(node, sourceFile, projectRoot));
|
|
34
|
+
}
|
|
35
|
+
if ("children" in node) {
|
|
36
|
+
for (const child of node.children)
|
|
37
|
+
visit(child);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
visit(tree);
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** Adds the same identity through Astro's Sätteri visitor API. */
|
|
45
|
+
export function createSatteriIdentityPlugin(projectRoot) {
|
|
46
|
+
return {
|
|
47
|
+
name: "nudge-ui-markdown-identity",
|
|
48
|
+
options: { position: true },
|
|
49
|
+
element: {
|
|
50
|
+
filter: PROSE_TAGS,
|
|
51
|
+
visit(node, context) {
|
|
52
|
+
if (!context.fileURL || context.fileURL.protocol !== "file:")
|
|
53
|
+
return;
|
|
54
|
+
const file = fileURLToPath(context.fileURL);
|
|
55
|
+
if (!/\.mdx?$/.test(file))
|
|
56
|
+
return;
|
|
57
|
+
for (const [key, value] of Object.entries(attributesFor(node, file, projectRoot))) {
|
|
58
|
+
context.setProperty(node, key, value);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/** Extends supported processors without replacing the consumer's pipeline. */
|
|
65
|
+
export function installMarkdownIdentity(markdown, projectRoot) {
|
|
66
|
+
const processor = markdown.processor;
|
|
67
|
+
if (!processor)
|
|
68
|
+
return { rehypePlugins: [createMarkdownIdentityPlugin(projectRoot)] };
|
|
69
|
+
if (processor.name !== "unified" && processor.name !== "satteri")
|
|
70
|
+
return undefined;
|
|
71
|
+
// SAFETY: Astro's supported processors expose mutable plugin arrays. This
|
|
72
|
+
// adapter only appends plugins and does not inspect existing entries.
|
|
73
|
+
const options = processor.options;
|
|
74
|
+
if (processor.name === "unified") {
|
|
75
|
+
(options.rehypePlugins ??= []).push(createMarkdownIdentityPlugin(projectRoot));
|
|
76
|
+
}
|
|
77
|
+
else if (processor.name === "satteri") {
|
|
78
|
+
(options.hastPlugins ??= []).push(createSatteriIdentityPlugin(projectRoot));
|
|
79
|
+
}
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `NUDGE_UI` environment switch shared by every development host.
|
|
3
|
+
*
|
|
4
|
+
* - `0`, `false`, or `off` disables the host Adapter for that run.
|
|
5
|
+
* - `1`, `true`, or `on` also opens the editor in automated browsers, which
|
|
6
|
+
* otherwise receive the plain application.
|
|
7
|
+
*/
|
|
8
|
+
export type NudgeUiEnvironmentSwitch = "off" | "on" | null;
|
|
9
|
+
export declare function readNudgeUiEnvironmentSwitch(env?: Readonly<Record<string, string | undefined>>): NudgeUiEnvironmentSwitch;
|
|
10
|
+
/** An explicit `enabled: false` or `NUDGE_UI=0` disables the Adapter. */
|
|
11
|
+
export declare function isNudgeUiEnabled(enabled: boolean | undefined, env?: Readonly<Record<string, string | undefined>>): boolean;
|
|
12
|
+
/** Manifest fields derived from the environment at request time. */
|
|
13
|
+
export declare function automationManifestFields(env?: Readonly<Record<string, string | undefined>>): {
|
|
14
|
+
inspectAutomatedBrowsers?: true;
|
|
15
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function readNudgeUiEnvironmentSwitch(env = process.env) {
|
|
2
|
+
const value = env.NUDGE_UI?.trim().toLowerCase();
|
|
3
|
+
if (value === "0" || value === "false" || value === "off")
|
|
4
|
+
return "off";
|
|
5
|
+
if (value === "1" || value === "true" || value === "on")
|
|
6
|
+
return "on";
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
/** An explicit `enabled: false` or `NUDGE_UI=0` disables the Adapter. */
|
|
10
|
+
export function isNudgeUiEnabled(enabled, env = process.env) {
|
|
11
|
+
return enabled !== false && readNudgeUiEnvironmentSwitch(env) !== "off";
|
|
12
|
+
}
|
|
13
|
+
/** Manifest fields derived from the environment at request time. */
|
|
14
|
+
export function automationManifestFields(env = process.env) {
|
|
15
|
+
return readNudgeUiEnvironmentSwitch(env) === "on" ? { inspectAutomatedBrowsers: true } : {};
|
|
16
|
+
}
|
|
@@ -15,7 +15,7 @@ export function buildManifest(input) {
|
|
|
15
15
|
stylingSystem: "CSS custom properties",
|
|
16
16
|
// Canvas shares the Vite host's controller/renderer runtime (ADR-0006);
|
|
17
17
|
// the mount in every document bootstraps as a renderer inside cards.
|
|
18
|
-
capabilities: { canvas: true, componentSemantics: true },
|
|
18
|
+
capabilities: { canvas: true, componentSemantics: true, domNavigation: true },
|
|
19
19
|
tokenCatalog: [],
|
|
20
20
|
tokens: [],
|
|
21
21
|
tokenDiagnostics: [],
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { handleHtmlArtifactRequest } from "../../project/artifacts.js";
|
|
1
2
|
import { createServer } from "node:http";
|
|
2
3
|
import { createRequire } from "node:module";
|
|
3
4
|
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
@@ -9,6 +10,7 @@ import { createProjectFileWatcher, } from "../../project/files.js";
|
|
|
9
10
|
import { createProjectTokenSnapshot } from "../../project/tokens.js";
|
|
10
11
|
import { NUDGE_UI_CLIENT_PATH, NUDGE_UI_EDITOR_PATH, NUDGE_UI_MANIFEST_PATH, NUDGE_UI_RELOAD_PATH, NUDGE_UI_ROUTE_PREFIX, createNudgeUiEditorDocument, isNudgeUiEditorDocumentRequest, } from "../../transport/index.js";
|
|
11
12
|
import { startOptionalProjectBridge } from "../projectBridge.js";
|
|
13
|
+
import { automationManifestFields } from "../environment.js";
|
|
12
14
|
/**
|
|
13
15
|
* Loopback-only manifest/reload sidecar (ADR-0010).
|
|
14
16
|
*
|
|
@@ -264,6 +266,7 @@ export async function ensureSidecar(root, options = {}) {
|
|
|
264
266
|
...(options.projectBridgeAllowedOrigins
|
|
265
267
|
? { allowedOrigins: options.projectBridgeAllowedOrigins }
|
|
266
268
|
: {}),
|
|
269
|
+
info: (message) => console.info(message),
|
|
267
270
|
warn: (message) => console.warn(message),
|
|
268
271
|
}).then((bridge) => {
|
|
269
272
|
projectBridge = bridge;
|
|
@@ -297,7 +300,10 @@ export async function ensureSidecar(root, options = {}) {
|
|
|
297
300
|
contractsTimer = setTimeout(flushContracts, 120);
|
|
298
301
|
};
|
|
299
302
|
const server = createServer((req, res) => {
|
|
300
|
-
|
|
303
|
+
void handleHtmlArtifactRequest(req, res, fsRoot).then((handled) => {
|
|
304
|
+
if (!handled)
|
|
305
|
+
respond(req, res, () => manifest, () => generation, streams, receiveContracts);
|
|
306
|
+
});
|
|
301
307
|
});
|
|
302
308
|
const port = await new Promise((resolvePort, rejectPort) => {
|
|
303
309
|
server.once("error", rejectPort);
|
|
@@ -529,7 +535,11 @@ function respond(req, res, currentManifest, currentGeneration, streams, receiveC
|
|
|
529
535
|
if (url === NUDGE_UI_MANIFEST_PATH) {
|
|
530
536
|
// The served snapshot carries its revision so clients can reconcile
|
|
531
537
|
// against SSE notifications instead of guessing.
|
|
532
|
-
const body = `${JSON.stringify({
|
|
538
|
+
const body = `${JSON.stringify({
|
|
539
|
+
...currentManifest(),
|
|
540
|
+
revision: currentGeneration(),
|
|
541
|
+
...automationManifestFields(),
|
|
542
|
+
})}\n`;
|
|
533
543
|
res.writeHead(200, {
|
|
534
544
|
"content-type": "application/json",
|
|
535
545
|
"cache-control": "no-store",
|
|
@@ -28,6 +28,8 @@ export interface NudgeUiNextConfig {
|
|
|
28
28
|
}
|
|
29
29
|
/** Host-specific policy additions passed to the shared source compiler. */
|
|
30
30
|
export interface NudgeUiNextOptions {
|
|
31
|
+
/** `false` returns the configuration untouched. `NUDGE_UI=0` has the same effect for one run. */
|
|
32
|
+
readonly enabled?: boolean;
|
|
31
33
|
readonly componentProtocols?: ComponentModuleProtocols;
|
|
32
34
|
/** Authored workspace directories outside the Next.js application root. */
|
|
33
35
|
readonly sourceRoots?: readonly string[];
|
|
@@ -4,6 +4,7 @@ import { dirname, join, relative, resolve } from "node:path";
|
|
|
4
4
|
import { ensureSidecar } from "./sidecar.js";
|
|
5
5
|
import { buildManifest } from "./manifest.js";
|
|
6
6
|
import { nudgeUiRepositoryPackagePath } from "./repositoryScope.js";
|
|
7
|
+
import { isNudgeUiEnabled } from "../environment.js";
|
|
7
8
|
import { NUDGE_UI_EDITOR_QUERY_PARAM, NUDGE_UI_EDITOR_QUERY_VALUE, NUDGE_UI_ROUTE_PREFIX, } from "../../transport/index.js";
|
|
8
9
|
const NAMESPACE_PREFIX = NUDGE_UI_ROUTE_PREFIX.slice(0, -1);
|
|
9
10
|
const SUPPORTED_NEXT_RANGE = ">=15.3 <17";
|
|
@@ -104,7 +105,7 @@ export function withNudgeUi(config = {}, options = {}) {
|
|
|
104
105
|
: () => config;
|
|
105
106
|
return (phase) => {
|
|
106
107
|
const resolved = factory(phase);
|
|
107
|
-
if (!isDevelopmentEvaluation(phase))
|
|
108
|
+
if (!isDevelopmentEvaluation(phase) || !isNudgeUiEnabled(options.enabled))
|
|
108
109
|
return resolved;
|
|
109
110
|
return instrumentConfig(resolved, options);
|
|
110
111
|
};
|
|
@@ -8,6 +8,7 @@ export declare function startOptionalProjectBridge(input: {
|
|
|
8
8
|
readonly projectId: string;
|
|
9
9
|
readonly origin: string;
|
|
10
10
|
readonly allowedOrigins?: readonly string[];
|
|
11
|
+
readonly info?: (message: string) => void;
|
|
11
12
|
readonly warn?: (message: string) => void;
|
|
12
13
|
}): Promise<{
|
|
13
14
|
browser: ProjectBridgeBrowserConfig;
|
|
@@ -53,6 +53,7 @@ async function launchOptionalProjectBridge(input, key) {
|
|
|
53
53
|
await runtime.close().catch(() => undefined);
|
|
54
54
|
throw new Error("the project bridge returned a different project or origin");
|
|
55
55
|
}
|
|
56
|
+
input.info?.(`[nudge-ui] project bridge ready for ${input.projectId}`);
|
|
56
57
|
let closed = false;
|
|
57
58
|
return {
|
|
58
59
|
browser: { baseUrl: runtime.browser.bridgeUrl, autoConnect: true },
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { NUDGE_UI_MANIFEST_VERSION, NUDGE_UI_RELOAD_PATH } from "../../transport/index.js";
|
|
2
|
+
import { automationManifestFields } from "../environment.js";
|
|
2
3
|
export { NUDGE_UI_CLIENT_PATH, NUDGE_UI_EDITOR_PATH, NUDGE_UI_MANIFEST_PATH, NUDGE_UI_MOUNT_ID, NUDGE_UI_RELOAD_PATH, NUDGE_UI_ROUTE_PREFIX, } from "../../transport/index.js";
|
|
3
4
|
/**
|
|
4
5
|
* Creates the first valid static-HTML runtime snapshot.
|
|
@@ -23,7 +24,7 @@ export function createStandaloneRuntimeManifest(projectId, tokenSnapshot = empty
|
|
|
23
24
|
// Canvas shares the Vite host's controller/renderer runtime (ADR-0012):
|
|
24
25
|
// every served document carries the bootstrap, so card iframes boot as
|
|
25
26
|
// renderers without host-specific code.
|
|
26
|
-
capabilities: { canvas: true, componentSemantics: false },
|
|
27
|
+
capabilities: { canvas: true, componentSemantics: false, domNavigation: true },
|
|
27
28
|
tokenCatalog: tokenSnapshot.tokenCatalog,
|
|
28
29
|
tokens: tokenSnapshot.tokens,
|
|
29
30
|
tokenDiagnostics: tokenSnapshot.tokenDiagnostics,
|
|
@@ -39,6 +40,7 @@ export function createStandaloneRuntimeManifest(projectId, tokenSnapshot = empty
|
|
|
39
40
|
strategy: "reload-document",
|
|
40
41
|
events: ["ready", "reload"],
|
|
41
42
|
},
|
|
43
|
+
...automationManifestFields(),
|
|
42
44
|
};
|
|
43
45
|
}
|
|
44
46
|
function emptyTokenSnapshot() {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { handleHtmlArtifactRequest } from "../../project/artifacts.js";
|
|
1
2
|
import { createHash } from "node:crypto";
|
|
2
3
|
import { createServer, } from "node:http";
|
|
3
4
|
import { constants, existsSync, realpathSync, statSync, } from "node:fs";
|
|
@@ -157,6 +158,7 @@ export function createStandaloneServer(options) {
|
|
|
157
158
|
appRoot: rootDirectory,
|
|
158
159
|
projectId,
|
|
159
160
|
origin: address.url.replace(/\/$/, ""),
|
|
161
|
+
info: (message) => console.info(message),
|
|
160
162
|
warn: (message) => console.warn(message),
|
|
161
163
|
}).then((bridge) => {
|
|
162
164
|
projectBridge = bridge;
|
|
@@ -382,6 +384,8 @@ function isWithin(root, candidate) {
|
|
|
382
384
|
}
|
|
383
385
|
async function handleRequest(input) {
|
|
384
386
|
const { request, response } = input;
|
|
387
|
+
if (await handleHtmlArtifactRequest(request, response, input.rootDirectory))
|
|
388
|
+
return;
|
|
385
389
|
if (request.method !== "GET" && request.method !== "HEAD") {
|
|
386
390
|
sendText(response, 405, "Method Not Allowed", { Allow: "GET, HEAD" });
|
|
387
391
|
return;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Plugin } from "vite";
|
|
2
2
|
import type { TailwindV3Config, ThemeContract } from "../../css/dialects/index.js";
|
|
3
|
+
import { type NudgeUiRuntimeConfig } from "../../inspector/clientManifest.js";
|
|
3
4
|
import type { FrameworkHost, FrameworkSupport, ReactOptions } from "./react.js";
|
|
4
5
|
/**
|
|
5
6
|
* How to find the project's vanilla-extract theme contract. Loading a module
|
|
@@ -18,6 +19,7 @@ export interface VanillaExtractOptions {
|
|
|
18
19
|
source?: string;
|
|
19
20
|
}
|
|
20
21
|
export interface NudgeUiOptions extends ReactOptions {
|
|
22
|
+
/** `false` registers nothing. `NUDGE_UI=0` has the same effect for one run. */
|
|
21
23
|
enabled?: boolean;
|
|
22
24
|
/** Enables experimental DOM parent/child navigation in the Inspector. */
|
|
23
25
|
debug?: boolean;
|
|
@@ -27,6 +29,8 @@ export interface NudgeUiOptions extends ReactOptions {
|
|
|
27
29
|
demoPages?: readonly string[];
|
|
28
30
|
/** Labels for the seeded demo cards in display order, including the primary card. */
|
|
29
31
|
demoCardLabels?: readonly string[];
|
|
32
|
+
/** Product features exposed by the inspector runtime. Omitted flags remain enabled. */
|
|
33
|
+
features?: NudgeUiRuntimeConfig["features"];
|
|
30
34
|
/** Explicit project ID for browser-storage keys (defaults to root directory basename). */
|
|
31
35
|
projectId?: string;
|
|
32
36
|
/** Optional static v3 config for fixture/app integrations; dynamic configs are not executed. */
|
package/dist/hosts/vite/vite.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { handleHtmlArtifactRequest } from "../../project/artifacts.js";
|
|
1
2
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
2
3
|
import { createRequire } from "node:module";
|
|
3
4
|
import { basename, join, relative, resolve, sep, } from "node:path";
|
|
@@ -8,6 +9,7 @@ import { catalogSourcePath, createViteStylesheetArtifact, isHostApplicationSourc
|
|
|
8
9
|
import { interpretDialects } from "../../css/dialects/index.js";
|
|
9
10
|
import { detectStylingSystem, } from "../../inspector/clientManifest.js";
|
|
10
11
|
import { loopbackOrigin, startOptionalProjectBridge, } from "../projectBridge.js";
|
|
12
|
+
import { automationManifestFields, isNudgeUiEnabled } from "../environment.js";
|
|
11
13
|
function isRecord(value) {
|
|
12
14
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13
15
|
}
|
|
@@ -80,6 +82,8 @@ function scanCssFiles(rootDir, files = [], dir = rootDir, ignoredDirectory) {
|
|
|
80
82
|
export function transformIndexHtmlHtml(html, command, { debug = false, demoBuild = false, demo = false } = {}) {
|
|
81
83
|
if (command === "build" && !demoBuild)
|
|
82
84
|
return null;
|
|
85
|
+
if (html.includes("data-nudge-ui-client"))
|
|
86
|
+
return null;
|
|
83
87
|
const script = demo || demoBuild ? LEGACY_INSPECTOR_SCRIPT : INSPECTOR_SCRIPT;
|
|
84
88
|
const inject = `\n${debug ? DEBUG_MOUNT_DIV : MOUNT_DIV}\n${script}\n`;
|
|
85
89
|
if (html.includes("</body>")) {
|
|
@@ -101,7 +105,7 @@ function invalidateHmrModules(server, modules, timestamp) {
|
|
|
101
105
|
* here has grown a React assumption.
|
|
102
106
|
*/
|
|
103
107
|
export function createVitePlugins(options = {}, createFramework = null) {
|
|
104
|
-
const enabled = options.enabled
|
|
108
|
+
const enabled = isNudgeUiEnabled(options.enabled);
|
|
105
109
|
let root;
|
|
106
110
|
let buildOutputDirectory;
|
|
107
111
|
let command = "serve";
|
|
@@ -484,6 +488,7 @@ export function createVitePlugins(options = {}, createFramework = null) {
|
|
|
484
488
|
revision: 0,
|
|
485
489
|
runtime: buildRuntimeSnapshot(),
|
|
486
490
|
...(projectBridge ? { agentBridge: projectBridge.browser } : {}),
|
|
491
|
+
...automationManifestFields(),
|
|
487
492
|
};
|
|
488
493
|
}
|
|
489
494
|
function startProjectBridge(server) {
|
|
@@ -506,6 +511,7 @@ export function createVitePlugins(options = {}, createFramework = null) {
|
|
|
506
511
|
projectId: options.projectId ?? basename(root),
|
|
507
512
|
origin,
|
|
508
513
|
...(allowedOrigins.length > 0 ? { allowedOrigins } : {}),
|
|
514
|
+
info: (message) => server.config.logger.info(message),
|
|
509
515
|
warn: (message) => server.config.logger.warn(message),
|
|
510
516
|
}).then((bridge) => {
|
|
511
517
|
projectBridge = bridge;
|
|
@@ -530,7 +536,8 @@ export function createVitePlugins(options = {}, createFramework = null) {
|
|
|
530
536
|
...(options.demo === true ? { demo: true } : {}),
|
|
531
537
|
...(options.demoPages === undefined ? {} : { demoPages: options.demoPages }),
|
|
532
538
|
...(options.demoCardLabels === undefined ? {} : { demoCardLabels: options.demoCardLabels }),
|
|
533
|
-
|
|
539
|
+
...(options.features === undefined ? {} : { features: options.features }),
|
|
540
|
+
capabilities: { canvas: true, componentSemantics: framework !== null, domNavigation: true },
|
|
534
541
|
tokenCatalog: snapshot.definitions.map((definition) => ({
|
|
535
542
|
...definition,
|
|
536
543
|
declarations: definition.declarations.map((declaration) => ({ ...declaration })),
|
|
@@ -551,11 +558,24 @@ export function createVitePlugins(options = {}, createFramework = null) {
|
|
|
551
558
|
if (!enabled || env.command !== "serve")
|
|
552
559
|
return;
|
|
553
560
|
// Module resolution is a framework concern; without one this host asks nothing of the resolver.
|
|
554
|
-
|
|
561
|
+
const frameworkConfig = framework?.viteConfig({
|
|
555
562
|
projectRoot: userConfig.root ?? process.cwd(),
|
|
556
563
|
demo: options.demo === true,
|
|
557
564
|
existingDedupe: userConfig.resolve?.dedupe ?? [],
|
|
558
565
|
});
|
|
566
|
+
const ignored = userConfig.server?.watch?.ignored;
|
|
567
|
+
return {
|
|
568
|
+
...frameworkConfig,
|
|
569
|
+
server: {
|
|
570
|
+
watch: {
|
|
571
|
+
ignored: [
|
|
572
|
+
...(ignored === undefined ? [] : Array.isArray(ignored) ? ignored : [ignored]),
|
|
573
|
+
"**/.nudge",
|
|
574
|
+
"**/.nudge/**",
|
|
575
|
+
],
|
|
576
|
+
},
|
|
577
|
+
},
|
|
578
|
+
};
|
|
559
579
|
},
|
|
560
580
|
configResolved(config) {
|
|
561
581
|
root = config.root;
|
|
@@ -583,6 +603,8 @@ export function createVitePlugins(options = {}, createFramework = null) {
|
|
|
583
603
|
if (runtimeWarning)
|
|
584
604
|
server.config.logger.warn(runtimeWarning);
|
|
585
605
|
server.middlewares?.use(async (request, response, next) => {
|
|
606
|
+
if (await handleHtmlArtifactRequest(request, response, root ?? process.cwd(), (html) => server.transformIndexHtml(request.url ?? "/", html)))
|
|
607
|
+
return;
|
|
586
608
|
const pathname = new URL(request.url ?? "/", "http://nudge-ui.local").pathname;
|
|
587
609
|
const invalidReservedMethod = (pathname === CLIENT_PATH || pathname === MANIFEST_PATH)
|
|
588
610
|
? request.method !== "GET"
|
|
@@ -598,7 +620,7 @@ export function createVitePlugins(options = {}, createFramework = null) {
|
|
|
598
620
|
response.statusCode = 200;
|
|
599
621
|
response.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
600
622
|
response.setHeader("Cache-Control", "no-store");
|
|
601
|
-
response.end(request.method === "HEAD" ? undefined : createNudgeUiEditorDocument());
|
|
623
|
+
response.end(request.method === "HEAD" ? undefined : await server.transformIndexHtml(request.url ?? NUDGE_UI_EDITOR_PATH, createNudgeUiEditorDocument()));
|
|
602
624
|
return;
|
|
603
625
|
}
|
|
604
626
|
if (pathname === CLIENT_PATH) {
|
|
@@ -715,7 +737,8 @@ export function createVitePlugins(options = {}, createFramework = null) {
|
|
|
715
737
|
' demo: true,',
|
|
716
738
|
` demoPages: ${JSON.stringify(options.demoPages ?? [])},`,
|
|
717
739
|
` demoCardLabels: ${JSON.stringify(options.demoCardLabels ?? [])},`,
|
|
718
|
-
`
|
|
740
|
+
` features: ${JSON.stringify(options.features ?? {})},`,
|
|
741
|
+
` capabilities: { canvas: true, componentSemantics: ${String(framework !== null)}, domNavigation: true },`,
|
|
719
742
|
' tokenCatalog,',
|
|
720
743
|
' tokens,',
|
|
721
744
|
' tokenDiagnostics,',
|