dreamboard 0.1.21 → 0.1.23
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/dist/{chunk-EYYWGWTO.js → chunk-2RCUHMGL.js} +343 -1911
- package/dist/chunk-2RCUHMGL.js.map +1 -0
- package/dist/{chunk-MOVHYB6E.js → chunk-GN7232BY.js} +1025 -695
- package/dist/chunk-GN7232BY.js.map +1 -0
- package/dist/{chunk-BMYC6772.js → chunk-H3O43F5P.js} +9765 -3068
- package/dist/chunk-H3O43F5P.js.map +1 -0
- package/dist/dev-host/dev-api-proxy-plugin.ts +330 -0
- package/dist/dev-host/dev-diagnostics.ts +62 -0
- package/dist/dev-host/dev-fallback-stylesheet.ts +50 -0
- package/dist/dev-host/dev-host-controller.ts +686 -0
- package/dist/dev-host/dev-host-player-query.ts +17 -0
- package/dist/dev-host/dev-host-session-transport.ts +52 -0
- package/dist/dev-host/dev-host-storage.ts +56 -0
- package/dist/dev-host/dev-log-relay-plugin.ts +469 -0
- package/dist/dev-host/dev-runtime-config.ts +14 -0
- package/dist/dev-host/dev-runtime-platform.ts +419 -0
- package/dist/dev-host/dev-virtual-modules-plugin.ts +63 -0
- package/dist/dev-host/host-main.css +182 -0
- package/dist/dev-host/host-main.tsx +754 -0
- package/dist/dev-host/index.html +56 -0
- package/dist/dev-host/plugin-main.ts +55 -0
- package/dist/dev-host/plugin.html +24 -0
- package/dist/dev-host/start-dev-server.ts +138 -0
- package/dist/dev-host/virtual-modules.d.ts +27 -0
- package/dist/dist-FEPN3BDN.js +16543 -0
- package/dist/dist-FEPN3BDN.js.map +1 -0
- package/dist/{dist-WJRJNFLI.js → dist-FRURQI7Q.js} +4 -2
- package/dist/index.js +3 -3
- package/dist/internal.js +159 -124
- package/dist/internal.js.map +1 -1
- package/dist/runtime-packages/tailwind-config/shared-styles.css +146 -0
- package/dist/runtime-packages/ui/src/components/.gitkeep +0 -0
- package/dist/runtime-packages/ui/src/components/accordion.tsx +66 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/actions.tsx +65 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/artifact.tsx +147 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/branch.tsx +215 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/canvas.tsx +22 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/chain-of-thought.tsx +228 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/code-block.tsx +179 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/confirmation.tsx +158 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/connection.tsx +28 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/context.tsx +408 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/controls.tsx +18 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/conversation.tsx +97 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/edge.tsx +140 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/image.tsx +24 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/inline-citation.tsx +287 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/loader.tsx +96 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/message.tsx +463 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/node.tsx +71 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/open-in-chat.tsx +365 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/panel.tsx +15 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/plan.tsx +142 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/prompt-input.tsx +1380 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/queue.tsx +274 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/reasoning.tsx +182 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/response.tsx +22 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/shimmer.tsx +64 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/sources.tsx +77 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/suggestion.tsx +53 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/task.tsx +87 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/tool.tsx +165 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/toolbar.tsx +16 -0
- package/dist/runtime-packages/ui/src/components/ai-elements/web-preview.tsx +263 -0
- package/dist/runtime-packages/ui/src/components/alert-dialog.tsx +157 -0
- package/dist/runtime-packages/ui/src/components/alert.tsx +66 -0
- package/dist/runtime-packages/ui/src/components/avatar.tsx +53 -0
- package/dist/runtime-packages/ui/src/components/badge.tsx +46 -0
- package/dist/runtime-packages/ui/src/components/button-group.tsx +83 -0
- package/dist/runtime-packages/ui/src/components/button.tsx +65 -0
- package/dist/runtime-packages/ui/src/components/card.tsx +92 -0
- package/dist/runtime-packages/ui/src/components/carousel.tsx +241 -0
- package/dist/runtime-packages/ui/src/components/collapsible.tsx +33 -0
- package/dist/runtime-packages/ui/src/components/command.tsx +184 -0
- package/dist/runtime-packages/ui/src/components/context-menu.tsx +252 -0
- package/dist/runtime-packages/ui/src/components/counter.tsx +11 -0
- package/dist/runtime-packages/ui/src/components/dialog.tsx +146 -0
- package/dist/runtime-packages/ui/src/components/drawer.tsx +132 -0
- package/dist/runtime-packages/ui/src/components/dropdown-menu.tsx +257 -0
- package/dist/runtime-packages/ui/src/components/form.tsx +168 -0
- package/dist/runtime-packages/ui/src/components/header.tsx +13 -0
- package/dist/runtime-packages/ui/src/components/hover-card.tsx +44 -0
- package/dist/runtime-packages/ui/src/components/input-group.tsx +178 -0
- package/dist/runtime-packages/ui/src/components/input.tsx +21 -0
- package/dist/runtime-packages/ui/src/components/item.tsx +193 -0
- package/dist/runtime-packages/ui/src/components/label.tsx +24 -0
- package/dist/runtime-packages/ui/src/components/navigation-menu.tsx +168 -0
- package/dist/runtime-packages/ui/src/components/popover.tsx +55 -0
- package/dist/runtime-packages/ui/src/components/progress.tsx +31 -0
- package/dist/runtime-packages/ui/src/components/radio-group.tsx +45 -0
- package/dist/runtime-packages/ui/src/components/resizable.tsx +56 -0
- package/dist/runtime-packages/ui/src/components/scroll-area.tsx +58 -0
- package/dist/runtime-packages/ui/src/components/select.tsx +187 -0
- package/dist/runtime-packages/ui/src/components/separator.tsx +28 -0
- package/dist/runtime-packages/ui/src/components/skeleton.tsx +13 -0
- package/dist/runtime-packages/ui/src/components/sonner.tsx +25 -0
- package/dist/runtime-packages/ui/src/components/spinner.tsx +16 -0
- package/dist/runtime-packages/ui/src/components/switch.tsx +31 -0
- package/dist/runtime-packages/ui/src/components/table.tsx +137 -0
- package/dist/runtime-packages/ui/src/components/tabs.tsx +74 -0
- package/dist/runtime-packages/ui/src/components/textarea.tsx +23 -0
- package/dist/runtime-packages/ui/src/components/theme-provider.tsx +73 -0
- package/dist/runtime-packages/ui/src/components/tooltip.tsx +61 -0
- package/dist/runtime-packages/ui/src/components/ui/file-upload.tsx +195 -0
- package/dist/runtime-packages/ui/src/hooks/.gitkeep +0 -0
- package/dist/runtime-packages/ui/src/index.ts +68 -0
- package/dist/runtime-packages/ui/src/lib/utils.ts +6 -0
- package/dist/runtime-packages/ui-host-runtime/src/actor-principal.ts +68 -0
- package/dist/runtime-packages/ui-host-runtime/src/components/host-controls.tsx +359 -0
- package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback-toaster.tsx +274 -0
- package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback.tsx +214 -0
- package/dist/runtime-packages/ui-host-runtime/src/components/host-session-metadata.tsx +135 -0
- package/dist/runtime-packages/ui-host-runtime/src/components/index.ts +5 -0
- package/dist/runtime-packages/ui-host-runtime/src/components/perf-overlay.tsx +194 -0
- package/dist/runtime-packages/ui-host-runtime/src/host-controls.tsx +1 -0
- package/dist/runtime-packages/ui-host-runtime/src/host-feedback.tsx +1 -0
- package/dist/runtime-packages/ui-host-runtime/src/host-session-transport.ts +162 -0
- package/dist/runtime-packages/ui-host-runtime/src/index.ts +2 -0
- package/dist/runtime-packages/ui-host-runtime/src/logger.ts +11 -0
- package/dist/runtime-packages/ui-host-runtime/src/perf.ts +253 -0
- package/dist/runtime-packages/ui-host-runtime/src/plugin-bridge.ts +195 -0
- package/dist/runtime-packages/ui-host-runtime/src/plugin-health-check.ts +138 -0
- package/dist/runtime-packages/ui-host-runtime/src/plugin-messages.ts +159 -0
- package/dist/runtime-packages/ui-host-runtime/src/plugin-session-gateway.ts +524 -0
- package/dist/runtime-packages/ui-host-runtime/src/runtime/index.ts +12 -0
- package/dist/runtime-packages/ui-host-runtime/src/screenshot/projection-to-snapshot.ts +122 -0
- package/dist/runtime-packages/ui-host-runtime/src/screenshot/static-store-api.ts +26 -0
- package/dist/runtime-packages/ui-host-runtime/src/session-ingress-controller.ts +477 -0
- package/dist/runtime-packages/ui-host-runtime/src/session-ingress.ts +209 -0
- package/dist/runtime-packages/ui-host-runtime/src/session-live-runtime.ts +112 -0
- package/dist/runtime-packages/ui-host-runtime/src/session-model.ts +318 -0
- package/dist/runtime-packages/ui-host-runtime/src/session-projection.ts +211 -0
- package/dist/runtime-packages/ui-host-runtime/src/session-state-reducer.ts +814 -0
- package/dist/runtime-packages/ui-host-runtime/src/sse-manager.ts +334 -0
- package/dist/runtime-packages/ui-host-runtime/src/unified-session-store.ts +180 -0
- package/dist/scaffold/assets/static/app/tsconfig.framework.json +3 -1
- package/dist/scaffold/assets/static/ui/tsconfig.framework.json +7 -19
- package/package.json +52 -17
- package/skills/dreamboard/SKILL.md +41 -75
- package/LICENSE +0 -89
- package/NOTICE +0 -1
- package/dist/chunk-BMYC6772.js.map +0 -1
- package/dist/chunk-EYYWGWTO.js.map +0 -1
- package/dist/chunk-MOVHYB6E.js.map +0 -1
- package/dist/scaffold/assets/static/ui/App.tsx +0 -22
- package/dist/src-CUL7EGGG.js +0 -634
- package/dist/src-CUL7EGGG.js.map +0 -1
- package/skills/dreamboard/references/authoring-lifecycle.md +0 -102
- package/skills/dreamboard/references/board-surfaces.md +0 -36
- package/skills/dreamboard/references/board-topology.md +0 -443
- package/skills/dreamboard/references/boards-and-topology.md +0 -100
- package/skills/dreamboard/references/card-actions.md +0 -107
- package/skills/dreamboard/references/cli.md +0 -120
- package/skills/dreamboard/references/core-concepts.md +0 -514
- package/skills/dreamboard/references/custom-renderers.md +0 -26
- package/skills/dreamboard/references/derived-values.md +0 -55
- package/skills/dreamboard/references/effects.md +0 -111
- package/skills/dreamboard/references/game-contract.md +0 -89
- package/skills/dreamboard/references/game-definition.md +0 -89
- package/skills/dreamboard/references/game-shell.md +0 -80
- package/skills/dreamboard/references/hand-surfaces.md +0 -33
- package/skills/dreamboard/references/index.md +0 -112
- package/skills/dreamboard/references/inputs-and-targets.md +0 -160
- package/skills/dreamboard/references/interactions.md +0 -158
- package/skills/dreamboard/references/manifest-fields.md +0 -137
- package/skills/dreamboard/references/manifest.md +0 -81
- package/skills/dreamboard/references/package-surfaces.md +0 -69
- package/skills/dreamboard/references/phases.md +0 -145
- package/skills/dreamboard/references/prompts-and-choices.md +0 -55
- package/skills/dreamboard/references/quickstart.md +0 -71
- package/skills/dreamboard/references/rule-authoring.md +0 -144
- package/skills/dreamboard/references/setup-bootstrap.md +0 -78
- package/skills/dreamboard/references/stages-and-zones.md +0 -59
- package/skills/dreamboard/references/static-views.md +0 -67
- package/skills/dreamboard/references/table-queries-and-ops.md +0 -103
- package/skills/dreamboard/references/testing-bases.md +0 -147
- package/skills/dreamboard/references/testing-generated-contracts.md +0 -142
- package/skills/dreamboard/references/testing-runtime-assertions.md +0 -124
- package/skills/dreamboard/references/testing-scenarios.md +0 -148
- package/skills/dreamboard/references/testing-ui-tests.md +0 -174
- package/skills/dreamboard/references/testing.md +0 -161
- package/skills/dreamboard/references/ui-architecture.md +0 -137
- package/skills/dreamboard/references/ui-components.md +0 -34
- package/skills/dreamboard/references/views.md +0 -72
- package/skills/dreamboard/references/workspace-layout.md +0 -136
- /package/dist/{dist-WJRJNFLI.js.map → dist-FRURQI7Q.js.map} +0 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reverse-proxy plugin for the `dreamboard dev` Vite server.
|
|
3
|
+
*
|
|
4
|
+
* Every `/api/*` request the browser makes is intercepted here, run
|
|
5
|
+
* through `ensureFreshAccessToken` so the CLI's stored Supabase session
|
|
6
|
+
* is refreshed when needed, and forwarded to the configured upstream
|
|
7
|
+
* backend with an `Authorization: Bearer <fresh-token>` header injected
|
|
8
|
+
* on the wire. The access and refresh tokens never reach the browser.
|
|
9
|
+
*
|
|
10
|
+
* Failure contract:
|
|
11
|
+
* - Permanent refresh failure (stored refresh token invalid) responds
|
|
12
|
+
* with `401 { error: "session_invalid", message }` so the browser can
|
|
13
|
+
* show a "Run dreamboard login" overlay instead of surfacing a
|
|
14
|
+
* confusing upstream 401.
|
|
15
|
+
* - Transient refresh failure (network blip) falls back to the snapshot
|
|
16
|
+
* access token in `ResolvedConfig` when we still have one - this lets
|
|
17
|
+
* a short outage degrade to "existing token" behavior instead of
|
|
18
|
+
* blocking the iframe outright.
|
|
19
|
+
* - Upstream connection failure responds with `502 { error:
|
|
20
|
+
* "upstream_unavailable", message }`.
|
|
21
|
+
*
|
|
22
|
+
* The proxy is deliberately unaware of the session file / persist
|
|
23
|
+
* endpoint / log relay; those live in `dev-log-relay-plugin.ts`.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import http, { type IncomingMessage, type ServerResponse } from "node:http";
|
|
27
|
+
import https from "node:https";
|
|
28
|
+
import { EventEmitter } from "node:events";
|
|
29
|
+
import consola from "consola";
|
|
30
|
+
import type { Plugin } from "vite";
|
|
31
|
+
import {
|
|
32
|
+
DEFAULT_REFRESH_WINDOW_MS,
|
|
33
|
+
ensureFreshAccessToken,
|
|
34
|
+
} from "../auth/refresh-coordinator.js";
|
|
35
|
+
import { PermanentRefreshError } from "../auth/refresh-error.js";
|
|
36
|
+
import type { ResolvedConfig } from "../types.js";
|
|
37
|
+
|
|
38
|
+
export type ResolvedBearerOk = {
|
|
39
|
+
readonly kind: "ok";
|
|
40
|
+
readonly token: string | null;
|
|
41
|
+
};
|
|
42
|
+
export type ResolvedBearerPermanentFailure = {
|
|
43
|
+
readonly kind: "permanent_invalid";
|
|
44
|
+
readonly message: string;
|
|
45
|
+
};
|
|
46
|
+
export type ResolvedBearer = ResolvedBearerOk | ResolvedBearerPermanentFailure;
|
|
47
|
+
|
|
48
|
+
export interface DevApiProxyPluginDeps {
|
|
49
|
+
/**
|
|
50
|
+
* Hook point for tests: resolve the bearer token (or a permanent
|
|
51
|
+
* failure) synchronously once per request.
|
|
52
|
+
*/
|
|
53
|
+
resolveBearer?: (config: ResolvedConfig) => Promise<ResolvedBearer>;
|
|
54
|
+
/**
|
|
55
|
+
* Hook point for tests: construct the underlying proxy. Allows
|
|
56
|
+
* injecting an in-memory proxy that talks to a fake upstream.
|
|
57
|
+
*/
|
|
58
|
+
createProxy?: (target: string) => DevApiProxy;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type DevApiProxy = {
|
|
62
|
+
on(event: "error", listener: ProxyErrorListener): DevApiProxy;
|
|
63
|
+
web(
|
|
64
|
+
req: IncomingMessage,
|
|
65
|
+
res: ServerResponse,
|
|
66
|
+
options?: Record<string, never>,
|
|
67
|
+
callback?: (err?: Error) => void,
|
|
68
|
+
): void;
|
|
69
|
+
close(): void;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
type ProxyErrorListener = (
|
|
73
|
+
err: Error,
|
|
74
|
+
req: IncomingMessage,
|
|
75
|
+
res: ServerResponse,
|
|
76
|
+
) => void;
|
|
77
|
+
|
|
78
|
+
export function createDevApiProxyPlugin(options: {
|
|
79
|
+
config: ResolvedConfig;
|
|
80
|
+
deps?: DevApiProxyPluginDeps;
|
|
81
|
+
}): Plugin {
|
|
82
|
+
const { config, deps } = options;
|
|
83
|
+
const target = config.apiBaseUrl;
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
name: "dreamboard-dev-api-proxy",
|
|
87
|
+
configureServer(server) {
|
|
88
|
+
const createProxy =
|
|
89
|
+
deps?.createProxy ??
|
|
90
|
+
((proxyTarget: string) => createStreamingProxy(proxyTarget));
|
|
91
|
+
|
|
92
|
+
const proxy = createProxy(target);
|
|
93
|
+
|
|
94
|
+
proxy.on("error", (err, _req, res) => {
|
|
95
|
+
consola.debug(`[dev-proxy] upstream error: ${formatUnknown(err)}`);
|
|
96
|
+
if (res instanceof Object && "writeHead" in res && !res.headersSent) {
|
|
97
|
+
respondUpstreamUnavailable(res as ServerResponse, err);
|
|
98
|
+
} else if (res && "destroy" in res) {
|
|
99
|
+
(res as { destroy: () => void }).destroy();
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
const resolveBearer = deps?.resolveBearer ?? resolveDevBearer;
|
|
104
|
+
|
|
105
|
+
// NOTE: we intentionally do NOT mount this middleware on `/api`.
|
|
106
|
+
// Connect-style `middlewares.use(path, handler)` strips the mount
|
|
107
|
+
// prefix from `req.url` before invoking the handler, which would
|
|
108
|
+
// cause the proxy to forward `/sessions/.../status` instead of
|
|
109
|
+
// `/api/sessions/.../status` and the backend would respond 404.
|
|
110
|
+
// Filtering inside the handler keeps the full path intact.
|
|
111
|
+
server.middlewares.use((req, res, next) => {
|
|
112
|
+
if (!req.url || !isApiRequest(req.url)) {
|
|
113
|
+
next();
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
void handleApiRequest({ req, res, config, proxy, resolveBearer });
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
server.httpServer?.once("close", () => {
|
|
120
|
+
proxy.close();
|
|
121
|
+
});
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function handleApiRequest(options: {
|
|
127
|
+
req: IncomingMessage;
|
|
128
|
+
res: ServerResponse;
|
|
129
|
+
config: ResolvedConfig;
|
|
130
|
+
proxy: DevApiProxy;
|
|
131
|
+
resolveBearer: (config: ResolvedConfig) => Promise<ResolvedBearer>;
|
|
132
|
+
}): Promise<void> {
|
|
133
|
+
const { req, res, config, proxy, resolveBearer } = options;
|
|
134
|
+
try {
|
|
135
|
+
const bearer = await resolveBearer(config);
|
|
136
|
+
if (bearer.kind === "permanent_invalid") {
|
|
137
|
+
respondSessionInvalid(res, bearer.message);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (bearer.token) {
|
|
142
|
+
req.headers.authorization = `Bearer ${bearer.token}`;
|
|
143
|
+
} else {
|
|
144
|
+
delete req.headers.authorization;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
proxy.web(req, res, {}, (err) => {
|
|
148
|
+
if (!err) return;
|
|
149
|
+
consola.debug(`[dev-proxy] forward error: ${formatUnknown(err)}`);
|
|
150
|
+
if (!res.headersSent) {
|
|
151
|
+
respondUpstreamUnavailable(res, err);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
} catch (err) {
|
|
155
|
+
consola.debug(`[dev-proxy] pre-forward error: ${formatUnknown(err)}`);
|
|
156
|
+
respondRefreshFailed(res, err);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function createStreamingProxy(target: string): DevApiProxy {
|
|
161
|
+
const targetUrl = new URL(target);
|
|
162
|
+
const events = new EventEmitter();
|
|
163
|
+
const activeRequests = new Set<http.ClientRequest>();
|
|
164
|
+
|
|
165
|
+
const proxy: DevApiProxy = {
|
|
166
|
+
on(event, listener) {
|
|
167
|
+
events.on(event, listener);
|
|
168
|
+
return proxy;
|
|
169
|
+
},
|
|
170
|
+
web(req, res, _options, callback) {
|
|
171
|
+
const upstreamUrl = new URL(req.url ?? "/", targetUrl);
|
|
172
|
+
const headers = createForwardHeaders(req, targetUrl);
|
|
173
|
+
|
|
174
|
+
const client = targetUrl.protocol === "https:" ? https : http;
|
|
175
|
+
const upstreamReq = client.request(
|
|
176
|
+
upstreamUrl,
|
|
177
|
+
{
|
|
178
|
+
method: req.method,
|
|
179
|
+
headers,
|
|
180
|
+
},
|
|
181
|
+
(upstreamRes) => {
|
|
182
|
+
res.writeHead(
|
|
183
|
+
upstreamRes.statusCode ?? 502,
|
|
184
|
+
upstreamRes.statusMessage,
|
|
185
|
+
upstreamRes.headers,
|
|
186
|
+
);
|
|
187
|
+
upstreamRes.pipe(res);
|
|
188
|
+
},
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
activeRequests.add(upstreamReq);
|
|
192
|
+
|
|
193
|
+
const handleError = (err: Error) => {
|
|
194
|
+
activeRequests.delete(upstreamReq);
|
|
195
|
+
callback?.(err);
|
|
196
|
+
events.emit("error", err, req, res);
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
upstreamReq.on("error", handleError);
|
|
200
|
+
upstreamReq.on("close", () => activeRequests.delete(upstreamReq));
|
|
201
|
+
req.on("aborted", () => upstreamReq.destroy());
|
|
202
|
+
req.pipe(upstreamReq);
|
|
203
|
+
},
|
|
204
|
+
close() {
|
|
205
|
+
for (const request of activeRequests) {
|
|
206
|
+
request.destroy();
|
|
207
|
+
}
|
|
208
|
+
activeRequests.clear();
|
|
209
|
+
events.removeAllListeners();
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
return proxy;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function createForwardHeaders(
|
|
217
|
+
req: IncomingMessage,
|
|
218
|
+
targetUrl: URL,
|
|
219
|
+
): http.OutgoingHttpHeaders {
|
|
220
|
+
const headers: http.OutgoingHttpHeaders = { ...req.headers };
|
|
221
|
+
|
|
222
|
+
// Browser requests are same-origin with the dev host. Once the CLI proxies
|
|
223
|
+
// them to the backend, they are server-to-server requests; forwarding the
|
|
224
|
+
// browser Origin from a Cloudflare/LAN host makes backend CORS reject valid
|
|
225
|
+
// dev traffic.
|
|
226
|
+
delete headers.origin;
|
|
227
|
+
delete headers["access-control-request-headers"];
|
|
228
|
+
delete headers["access-control-request-method"];
|
|
229
|
+
|
|
230
|
+
headers.host = targetUrl.host;
|
|
231
|
+
headers["x-forwarded-host"] = req.headers.host;
|
|
232
|
+
headers["x-forwarded-proto"] = targetUrl.protocol.replace(":", "");
|
|
233
|
+
|
|
234
|
+
return headers;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export async function resolveDevBearer(
|
|
238
|
+
config: ResolvedConfig,
|
|
239
|
+
): Promise<ResolvedBearer> {
|
|
240
|
+
// Env/flag-provided tokens are not owned by `CredentialStore` and must
|
|
241
|
+
// not be rotated. Forward them as-is.
|
|
242
|
+
if (!usesStoredSession(config)) {
|
|
243
|
+
return { kind: "ok", token: config.authToken ?? null };
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (!config.supabaseUrl || !config.supabaseAnonKey) {
|
|
247
|
+
return { kind: "ok", token: config.authToken ?? null };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
try {
|
|
251
|
+
const result = await ensureFreshAccessToken({
|
|
252
|
+
supabaseUrl: config.supabaseUrl,
|
|
253
|
+
supabaseAnonKey: config.supabaseAnonKey,
|
|
254
|
+
refreshWindowMs: DEFAULT_REFRESH_WINDOW_MS,
|
|
255
|
+
});
|
|
256
|
+
switch (result.kind) {
|
|
257
|
+
case "missing":
|
|
258
|
+
return { kind: "ok", token: config.authToken ?? null };
|
|
259
|
+
case "unchanged":
|
|
260
|
+
case "rotated":
|
|
261
|
+
return { kind: "ok", token: result.credentials.accessToken };
|
|
262
|
+
case "transient_failure":
|
|
263
|
+
return { kind: "ok", token: config.authToken ?? null };
|
|
264
|
+
}
|
|
265
|
+
} catch (err) {
|
|
266
|
+
if (err instanceof PermanentRefreshError) {
|
|
267
|
+
return { kind: "permanent_invalid", message: err.message };
|
|
268
|
+
}
|
|
269
|
+
throw err;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function usesStoredSession(config: ResolvedConfig): boolean {
|
|
274
|
+
return (
|
|
275
|
+
config.authTokenSource === "global" &&
|
|
276
|
+
config.refreshTokenSource === "global"
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function respondSessionInvalid(res: ServerResponse, message: string): void {
|
|
281
|
+
if (res.headersSent) return;
|
|
282
|
+
res.statusCode = 401;
|
|
283
|
+
res.setHeader("content-type", "application/json");
|
|
284
|
+
res.end(
|
|
285
|
+
JSON.stringify({
|
|
286
|
+
error: "session_invalid",
|
|
287
|
+
message,
|
|
288
|
+
}),
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function respondUpstreamUnavailable(res: ServerResponse, error: unknown): void {
|
|
293
|
+
if (res.headersSent) return;
|
|
294
|
+
res.statusCode = 502;
|
|
295
|
+
res.setHeader("content-type", "application/json");
|
|
296
|
+
res.end(
|
|
297
|
+
JSON.stringify({
|
|
298
|
+
error: "upstream_unavailable",
|
|
299
|
+
message: formatUnknown(error),
|
|
300
|
+
}),
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function respondRefreshFailed(res: ServerResponse, error: unknown): void {
|
|
305
|
+
if (res.headersSent) return;
|
|
306
|
+
res.statusCode = 502;
|
|
307
|
+
res.setHeader("content-type", "application/json");
|
|
308
|
+
res.end(
|
|
309
|
+
JSON.stringify({
|
|
310
|
+
error: "refresh_failed",
|
|
311
|
+
message: formatUnknown(error),
|
|
312
|
+
}),
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function isApiRequest(url: string): boolean {
|
|
317
|
+
return url === "/api" || url.startsWith("/api/") || url.startsWith("/api?");
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function formatUnknown(value: unknown): string {
|
|
321
|
+
if (value instanceof Error) {
|
|
322
|
+
return value.message || value.name || "Unknown error";
|
|
323
|
+
}
|
|
324
|
+
if (typeof value === "string") return value;
|
|
325
|
+
try {
|
|
326
|
+
return JSON.stringify(value);
|
|
327
|
+
} catch {
|
|
328
|
+
return String(value);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { LoggerLike } from "@dreamboard/ui-host-runtime/runtime";
|
|
2
|
+
|
|
3
|
+
export type DevLogEnvelope = {
|
|
4
|
+
source: "host" | "plugin" | "sse";
|
|
5
|
+
level: "log" | "warn" | "error" | "info";
|
|
6
|
+
message: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type DevDiagnosticsLevel = "errors" | "verbose";
|
|
10
|
+
|
|
11
|
+
export function resolveDevDiagnosticsLevel(
|
|
12
|
+
debug: boolean,
|
|
13
|
+
): DevDiagnosticsLevel {
|
|
14
|
+
return debug ? "verbose" : "errors";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function createDevDiagnosticsLogger(
|
|
18
|
+
level: DevDiagnosticsLevel,
|
|
19
|
+
): LoggerLike {
|
|
20
|
+
if (level === "verbose") {
|
|
21
|
+
return {
|
|
22
|
+
log: (...args) => console.log(...args),
|
|
23
|
+
warn: (...args) => console.warn(...args),
|
|
24
|
+
error: (...args) => console.error(...args),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
log: () => {},
|
|
30
|
+
warn: () => {},
|
|
31
|
+
error: (...args) => console.error(...args),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function shouldRelayDevLog(
|
|
36
|
+
diagnosticsLevel: DevDiagnosticsLevel,
|
|
37
|
+
payload: DevLogEnvelope,
|
|
38
|
+
): boolean {
|
|
39
|
+
return (
|
|
40
|
+
diagnosticsLevel === "verbose" ||
|
|
41
|
+
payload.level === "warn" ||
|
|
42
|
+
payload.level === "error"
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function formatConsoleArgs(args: unknown[]): string {
|
|
47
|
+
return args.map((value) => stringifyForRelay(value)).join(" ");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function stringifyForRelay(value: unknown): string {
|
|
51
|
+
if (typeof value === "string") {
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
if (value instanceof Error) {
|
|
55
|
+
return value.stack ?? value.message;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
return JSON.stringify(value);
|
|
59
|
+
} catch {
|
|
60
|
+
return String(value);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { normalizePath } from "vite";
|
|
5
|
+
|
|
6
|
+
export function prepareFallbackStylesheet(options: {
|
|
7
|
+
projectRoot: string;
|
|
8
|
+
repoRoot: string;
|
|
9
|
+
}): string | null {
|
|
10
|
+
const projectStylePath = path.resolve(options.projectRoot, "ui/style.css");
|
|
11
|
+
if (existsSync(projectStylePath)) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const generatedDir = path.resolve(options.repoRoot, ".dreamboard-dev");
|
|
16
|
+
mkdirSync(generatedDir, { recursive: true });
|
|
17
|
+
|
|
18
|
+
const fingerprint = createHash("sha256")
|
|
19
|
+
.update(options.projectRoot, "utf8")
|
|
20
|
+
.digest("hex")
|
|
21
|
+
.slice(0, 8);
|
|
22
|
+
const instanceId = randomUUID().replaceAll("-", "").slice(0, 8);
|
|
23
|
+
const generatedPath = path.join(
|
|
24
|
+
generatedDir,
|
|
25
|
+
`plugin-styles-${fingerprint}-${instanceId}.css`,
|
|
26
|
+
);
|
|
27
|
+
const sharedStylesPath = normalizePath(
|
|
28
|
+
path.resolve(options.repoRoot, "packages/ui-sdk/src/plugin-styles.css"),
|
|
29
|
+
);
|
|
30
|
+
const uiSourcePath = normalizePath(
|
|
31
|
+
path.resolve(options.projectRoot, "ui/**/*.{ts,tsx}"),
|
|
32
|
+
);
|
|
33
|
+
const sharedSourcePath = normalizePath(
|
|
34
|
+
path.resolve(options.projectRoot, "shared/**/*.{ts,tsx}"),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
writeFileSync(
|
|
38
|
+
generatedPath,
|
|
39
|
+
[
|
|
40
|
+
`@import "/@fs/${sharedStylesPath}";`,
|
|
41
|
+
"",
|
|
42
|
+
`@source "${uiSourcePath}";`,
|
|
43
|
+
`@source "${sharedSourcePath}";`,
|
|
44
|
+
"",
|
|
45
|
+
].join("\n"),
|
|
46
|
+
"utf8",
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
return generatedPath;
|
|
50
|
+
}
|