@ggui-ai/mcp-server 0.2.0-alpha.4 → 0.3.0-rc.0
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/admin-blueprints-transport.d.ts.map +1 -1
- package/dist/admin-blueprints-transport.js +2 -1
- package/dist/admin-oauth-providers-transport.d.ts.map +1 -1
- package/dist/admin-oauth-providers-transport.js +7 -5
- package/dist/api-renders-routes.d.ts +85 -0
- package/dist/api-renders-routes.d.ts.map +1 -0
- package/dist/api-renders-routes.js +372 -0
- package/dist/build-mcp.d.ts +1 -1
- package/dist/build-mcp.d.ts.map +1 -1
- package/dist/build-mcp.js +39 -5
- package/dist/code-routes.d.ts +47 -0
- package/dist/code-routes.d.ts.map +1 -0
- package/dist/code-routes.js +81 -0
- package/dist/code-store-fs.js +2 -2
- package/dist/console-auth.d.ts +10 -10
- package/dist/console-auth.d.ts.map +1 -1
- package/dist/console-auth.js +5 -5
- package/dist/console-blueprint-routes.d.ts +71 -0
- package/dist/console-blueprint-routes.d.ts.map +1 -0
- package/dist/console-blueprint-routes.js +348 -0
- package/dist/console-chat-routes.d.ts +80 -0
- package/dist/console-chat-routes.d.ts.map +1 -0
- package/dist/console-chat-routes.js +182 -0
- package/dist/console-config-routes.d.ts +37 -0
- package/dist/console-config-routes.d.ts.map +1 -0
- package/dist/console-config-routes.js +91 -0
- package/dist/console-headers.d.ts +1 -1
- package/dist/console-info-routes.d.ts +84 -0
- package/dist/console-info-routes.d.ts.map +1 -0
- package/dist/console-info-routes.js +135 -0
- package/dist/console-keys-routes.d.ts +50 -0
- package/dist/console-keys-routes.d.ts.map +1 -0
- package/dist/console-keys-routes.js +222 -0
- package/dist/console-llm-keys-routes.d.ts +47 -0
- package/dist/console-llm-keys-routes.d.ts.map +1 -0
- package/dist/console-llm-keys-routes.js +443 -0
- package/dist/console-mcp-tools-routes.d.ts +41 -0
- package/dist/console-mcp-tools-routes.d.ts.map +1 -0
- package/dist/console-mcp-tools-routes.js +60 -0
- package/dist/console-registry-routes.d.ts +66 -0
- package/dist/console-registry-routes.d.ts.map +1 -0
- package/dist/console-registry-routes.js +276 -0
- package/dist/console-session-routes.d.ts +89 -0
- package/dist/console-session-routes.d.ts.map +1 -0
- package/dist/console-session-routes.js +385 -0
- package/dist/console-sessions-routes.d.ts +52 -0
- package/dist/console-sessions-routes.d.ts.map +1 -0
- package/dist/console-sessions-routes.js +106 -0
- package/dist/console-static-routes.d.ts +54 -0
- package/dist/console-static-routes.d.ts.map +1 -0
- package/dist/console-static-routes.js +190 -0
- package/dist/console-theme-routes.d.ts +3 -3
- package/dist/console-theme-routes.js +1 -1
- package/dist/console-timeline.d.ts +5 -5
- package/dist/console-timeline.d.ts.map +1 -1
- package/dist/console-timeline.js +27 -26
- package/dist/console-welcome.js +2 -2
- package/dist/email-login.d.ts.map +1 -1
- package/dist/email-login.js +2 -3
- package/dist/ggui-session-channel/action-ingress.d.ts +54 -0
- package/dist/ggui-session-channel/action-ingress.d.ts.map +1 -0
- package/dist/ggui-session-channel/action-ingress.js +228 -0
- package/dist/ggui-session-channel/channel-subscriptions.d.ts +97 -0
- package/dist/ggui-session-channel/channel-subscriptions.d.ts.map +1 -0
- package/dist/ggui-session-channel/channel-subscriptions.js +224 -0
- package/dist/ggui-session-channel/internal-types.d.ts +102 -0
- package/dist/ggui-session-channel/internal-types.d.ts.map +1 -0
- package/dist/ggui-session-channel/internal-types.js +6 -0
- package/dist/ggui-session-channel/outbound.d.ts +81 -0
- package/dist/ggui-session-channel/outbound.d.ts.map +1 -0
- package/dist/ggui-session-channel/outbound.js +174 -0
- package/dist/ggui-session-channel/socket-router.d.ts +38 -0
- package/dist/ggui-session-channel/socket-router.d.ts.map +1 -0
- package/dist/ggui-session-channel/socket-router.js +213 -0
- package/dist/ggui-session-channel/subscribe.d.ts +165 -0
- package/dist/ggui-session-channel/subscribe.d.ts.map +1 -0
- package/dist/ggui-session-channel/subscribe.js +370 -0
- package/dist/ggui-session-channel/subscriber-lifecycle.d.ts +40 -0
- package/dist/ggui-session-channel/subscriber-lifecycle.d.ts.map +1 -0
- package/dist/ggui-session-channel/subscriber-lifecycle.js +123 -0
- package/dist/ggui-session-channel.d.ts +425 -0
- package/dist/ggui-session-channel.d.ts.map +1 -0
- package/dist/ggui-session-channel.js +262 -0
- package/dist/health-routes.d.ts +76 -0
- package/dist/health-routes.d.ts.map +1 -0
- package/dist/health-routes.js +145 -0
- package/dist/index.d.ts +10 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -9
- package/dist/instructions-presets.d.ts +3 -3
- package/dist/instructions-presets.js +24 -24
- package/dist/llm-backed-negotiator.d.ts +68 -67
- package/dist/llm-backed-negotiator.d.ts.map +1 -1
- package/dist/llm-backed-negotiator.js +82 -221
- package/dist/mcp-apps-outbound.d.ts +47 -48
- package/dist/mcp-apps-outbound.d.ts.map +1 -1
- package/dist/mcp-apps-outbound.js +154 -177
- package/dist/mcp-endpoint-routes.d.ts +88 -0
- package/dist/mcp-endpoint-routes.d.ts.map +1 -0
- package/dist/mcp-endpoint-routes.js +359 -0
- package/dist/mcp-mounts.d.ts +2 -76
- package/dist/mcp-mounts.d.ts.map +1 -1
- package/dist/mcp-mounts.js +0 -76
- package/dist/oauth-as-routes.d.ts +60 -0
- package/dist/oauth-as-routes.d.ts.map +1 -0
- package/dist/oauth-as-routes.js +82 -0
- package/dist/oauth-clients-routes.d.ts +39 -0
- package/dist/oauth-clients-routes.d.ts.map +1 -0
- package/dist/oauth-clients-routes.js +87 -0
- package/dist/oauth-login-types.d.ts +1 -20
- package/dist/oauth-login-types.d.ts.map +1 -1
- package/dist/oauth-login-types.js +30 -7
- package/dist/oauth-login.d.ts.map +1 -1
- package/dist/oauth-login.js +3 -2
- package/dist/oauth-providers-store.d.ts.map +1 -1
- package/dist/oauth-providers-store.js +5 -5
- package/dist/oauth.d.ts +9 -8
- package/dist/oauth.d.ts.map +1 -1
- package/dist/oauth.js +41 -19
- package/dist/pairing-transport.d.ts.map +1 -1
- package/dist/pairing-transport.js +2 -1
- package/dist/request-context.d.ts +2 -2
- package/dist/request-context.js +2 -2
- package/dist/reserved-validators.d.ts.map +1 -1
- package/dist/reserved-validators.js +9 -1
- package/dist/route-param.d.ts +9 -0
- package/dist/route-param.d.ts.map +1 -0
- package/dist/route-param.js +10 -0
- package/dist/runtime-bundle-route.d.ts +43 -0
- package/dist/runtime-bundle-route.d.ts.map +1 -0
- package/dist/runtime-bundle-route.js +80 -0
- package/dist/schema-compat.d.ts +64 -62
- package/dist/schema-compat.d.ts.map +1 -1
- package/dist/schema-compat.js +23 -51
- package/dist/server.d.ts +179 -193
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +644 -3759
- package/dist/storage.d.ts +5 -5
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +5 -5
- package/dist/thread-transport.d.ts.map +1 -1
- package/dist/thread-transport.js +4 -3
- package/dist/user-session-auth.d.ts +7 -21
- package/dist/user-session-auth.d.ts.map +1 -1
- package/dist/user-session-auth.js +7 -28
- package/package.json +16 -15
- package/dist/mcp-apps-inbound.d.ts +0 -86
- package/dist/mcp-apps-inbound.d.ts.map +0 -1
- package/dist/mcp-apps-inbound.js +0 -283
- package/dist/render-channel.d.ts +0 -694
- package/dist/render-channel.d.ts.map +0 -1
- package/dist/render-channel.js +0 -1775
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Console blueprint resolution + try-live routes.
|
|
3
|
+
*
|
|
4
|
+
* GET /ggui/console/blueprint/:id — same-origin HTTP mirror of
|
|
5
|
+
* the `ggui_render_blueprint` MCP tool. Resolves a
|
|
6
|
+
* manifest-declared blueprint id to its compiled bundle +
|
|
7
|
+
* metadata via the wired `UiRegistry`; lets the SPA's
|
|
8
|
+
* `/preview/<id>` route mount the blueprint with a single fetch
|
|
9
|
+
* instead of negotiating a full MCP round-trip from the browser.
|
|
10
|
+
* POST /ggui/console/blueprint/:id/try — create a render, compile
|
|
11
|
+
* the blueprint's componentCode, commit a render with its full
|
|
12
|
+
* contract (actionSpec/streamSpec/propsSpec from the manifest),
|
|
13
|
+
* mint a shortCode, and return `{sessionId, shortCode, url}`.
|
|
14
|
+
* The returned `/s/<shortCode>` lands on the console's render
|
|
15
|
+
* viewer + subscribes to the render over `/ws`.
|
|
16
|
+
*
|
|
17
|
+
* Scope: registered only when a `UiRegistry` is present (same gate
|
|
18
|
+
* as the MCP render handler — no registry = no render path, no
|
|
19
|
+
* endpoint). No bearer auth: console routes are same-origin
|
|
20
|
+
* operator-facing; the operator already has OS access to the TSX
|
|
21
|
+
* sources this endpoint serves back.
|
|
22
|
+
*
|
|
23
|
+
* GET failure shape: { error, message } with a matching HTTP code.
|
|
24
|
+
* - 404 for unknown id OR known-id-no-bundle (source-only /
|
|
25
|
+
* compile-failed). The operator's remediation is the same in
|
|
26
|
+
* both cases (fix the manifest / fix the entry / fix the
|
|
27
|
+
* compile); splitting codes would add noise without signal.
|
|
28
|
+
* - 400 for malformed id parameters (empty, oversized).
|
|
29
|
+
*
|
|
30
|
+
* Shape symmetry: GET matches `GguiRenderBlueprintOutput` exactly, so
|
|
31
|
+
* the browser-side fetch can share a type import with MCP-tool
|
|
32
|
+
* callers without a translation layer.
|
|
33
|
+
*
|
|
34
|
+
* Try-live gates (all three required):
|
|
35
|
+
* - `uiRegistry` — blueprint resolution
|
|
36
|
+
* - `renderStore` — render persistence
|
|
37
|
+
* - `shortCodeIndex` — shortCode → render binding
|
|
38
|
+
*
|
|
39
|
+
* Partial gate (uiRegistry alone) → 503 with a remediation hint.
|
|
40
|
+
*/
|
|
41
|
+
import { randomBytes, randomUUID } from "node:crypto";
|
|
42
|
+
import { DEFAULT_BUILDER_APP_ID } from "./auth.js";
|
|
43
|
+
import { applyDevtoolSecurityHeaders } from "./console-headers.js";
|
|
44
|
+
import { checkRenderSchemaCompat, SchemaCompatError, } from "./schema-compat.js";
|
|
45
|
+
/**
|
|
46
|
+
* 18-char URL-safe shortCode for `POST /ggui/console/blueprint/:id/try`
|
|
47
|
+
* — visually distinct from the 16-char render-minted shortCodes in
|
|
48
|
+
* `@ggui-ai/mcp-server-handlers/renders/render.ts` so operators
|
|
49
|
+
* reading logs can tell a try-live render from an agent-rendered one
|
|
50
|
+
* at a glance. Same confusable-free alphabet
|
|
51
|
+
* (`[a-z0-9]` minus `1lI0Oo`) so the code stays hand-typable. Entropy
|
|
52
|
+
* ≈ 18 × log₂(31) ≈ 89 bits.
|
|
53
|
+
*/
|
|
54
|
+
function generateTryLiveShortCode() {
|
|
55
|
+
const alphabet = "abcdefghjkmnpqrstuvwxyz23456789";
|
|
56
|
+
const bytes = randomBytes(18);
|
|
57
|
+
let out = "";
|
|
58
|
+
for (let i = 0; i < 18; i += 1) {
|
|
59
|
+
out += alphabet[bytes[i] % alphabet.length];
|
|
60
|
+
}
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Mount `GET /ggui/console/blueprint/:id` +
|
|
65
|
+
* `POST /ggui/console/blueprint/:id/try` onto the express app.
|
|
66
|
+
* Returns nothing — the routes self-register.
|
|
67
|
+
*/
|
|
68
|
+
export function mountConsoleBlueprintRoutes(opts) {
|
|
69
|
+
const { app, uiRegistry, renderStore, shortCodeIndex, handlers, schemaCompatMode, logger } = opts;
|
|
70
|
+
if (renderStore && shortCodeIndex) {
|
|
71
|
+
const renderStoreForTry = renderStore;
|
|
72
|
+
const shortCodeIndexForTry = shortCodeIndex;
|
|
73
|
+
app.post("/ggui/console/blueprint/:id/try", async (req, res) => {
|
|
74
|
+
applyDevtoolSecurityHeaders(res);
|
|
75
|
+
const blueprintId = req.params["id"];
|
|
76
|
+
if (typeof blueprintId !== "string" || blueprintId.length === 0 || blueprintId.length > 256) {
|
|
77
|
+
res.status(400).json({
|
|
78
|
+
error: "invalid_request",
|
|
79
|
+
message: "`id` path parameter must be a non-empty string (≤256 chars)",
|
|
80
|
+
});
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const entry = await uiRegistry.get(blueprintId);
|
|
85
|
+
if (!entry) {
|
|
86
|
+
res.status(404).json({
|
|
87
|
+
error: "not_found",
|
|
88
|
+
message: `No blueprint registered with id "${blueprintId}". Check ggui.json#blueprints.include globs + ggui.ui.json#id values.`,
|
|
89
|
+
});
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const bundle = await uiRegistry.getBundle(blueprintId);
|
|
93
|
+
if (!bundle) {
|
|
94
|
+
res.status(404).json({
|
|
95
|
+
error: "bundle_not_available",
|
|
96
|
+
message: `Blueprint "${blueprintId}" (${entry.manifest.name}) has no bundle available. Either the TSX entry is missing or compile-on-demand failed.`,
|
|
97
|
+
});
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
// Materialize streamed bundles to a string — the render
|
|
101
|
+
// stores componentCode inline. Same rule the sibling GET
|
|
102
|
+
// endpoint applies.
|
|
103
|
+
let code;
|
|
104
|
+
if (typeof bundle.code === "string") {
|
|
105
|
+
code = bundle.code;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
const reader = bundle.code.getReader();
|
|
109
|
+
const decoder = new TextDecoder();
|
|
110
|
+
let out = "";
|
|
111
|
+
for (;;) {
|
|
112
|
+
const { done, value } = await reader.read();
|
|
113
|
+
if (done)
|
|
114
|
+
break;
|
|
115
|
+
if (typeof value === "string")
|
|
116
|
+
out += value;
|
|
117
|
+
else if (value instanceof Uint8Array)
|
|
118
|
+
out += decoder.decode(value, { stream: true });
|
|
119
|
+
}
|
|
120
|
+
out += decoder.decode();
|
|
121
|
+
code = out;
|
|
122
|
+
}
|
|
123
|
+
// Same default appId the CLI's pairing-authenticated /mcp
|
|
124
|
+
// ingress resolves for single-tenant OSS — the render is
|
|
125
|
+
// scoped to the same tenant.
|
|
126
|
+
const appId = DEFAULT_BUILDER_APP_ID;
|
|
127
|
+
// Phase B: a render IS the addressable unit; the prior
|
|
128
|
+
// (sessionId, stackItemId) pair collapses to a single
|
|
129
|
+
// sessionId. The blueprint id makes a natural slug; a
|
|
130
|
+
// same-blueprint retry replaces the row.
|
|
131
|
+
const sessionId = `try-${blueprintId}-${randomUUID()}`;
|
|
132
|
+
const createdAt = Date.now();
|
|
133
|
+
const contract = entry.manifest.contract ?? {};
|
|
134
|
+
const render = {
|
|
135
|
+
id: sessionId,
|
|
136
|
+
appId,
|
|
137
|
+
type: "component",
|
|
138
|
+
componentCode: code,
|
|
139
|
+
contentType: bundle.contentType,
|
|
140
|
+
eventSequence: 0,
|
|
141
|
+
createdAt,
|
|
142
|
+
lastActivityAt: createdAt,
|
|
143
|
+
expiresAt: createdAt + 24 * 60 * 60 * 1000,
|
|
144
|
+
description: `Blueprint try-live: ${entry.manifest.name}`,
|
|
145
|
+
// Data contract fields from the manifest. Each is
|
|
146
|
+
// conditionally spread — absent on the manifest →
|
|
147
|
+
// absent on the GguiSession (keeps shape honest + avoids
|
|
148
|
+
// an empty-shape contract tripping structural
|
|
149
|
+
// validators downstream).
|
|
150
|
+
...(contract.propsSpec ? { propsSpec: contract.propsSpec } : {}),
|
|
151
|
+
...(contract.actionSpec ? { actionSpec: contract.actionSpec } : {}),
|
|
152
|
+
...(contract.streamSpec ? { streamSpec: contract.streamSpec } : {}),
|
|
153
|
+
};
|
|
154
|
+
// Schema compatibility check. Fires BEFORE the render
|
|
155
|
+
// commits — if the blueprint's pre-declared actionSpec
|
|
156
|
+
// hints at a same-server tool whose schemas don't align,
|
|
157
|
+
// the operator gets a named `SCHEMA_MISMATCH_ERROR`
|
|
158
|
+
// response at registration time instead of an agent-side
|
|
159
|
+
// surprise on the first dispatched action. Mode sourced
|
|
160
|
+
// from `createGguiServer({schemaCompatCheck})`; defaults
|
|
161
|
+
// to `'reject'`. See `./schema-compat.ts`.
|
|
162
|
+
try {
|
|
163
|
+
const report = checkRenderSchemaCompat(render, handlers, schemaCompatMode, `console blueprint-try:${blueprintId}`);
|
|
164
|
+
if (!report.compatible) {
|
|
165
|
+
// Non-throwing path (mode === 'warn'): log with full
|
|
166
|
+
// detail so the operator has an observable surface.
|
|
167
|
+
logger.warn("schema_compat_warn", {
|
|
168
|
+
site: "console_blueprint_try",
|
|
169
|
+
blueprintId,
|
|
170
|
+
findingCount: report.findings.length,
|
|
171
|
+
findings: report.findings.map((f) => ({
|
|
172
|
+
kind: f.kind,
|
|
173
|
+
specName: f.specName,
|
|
174
|
+
toolName: f.toolName,
|
|
175
|
+
reason: f.reason,
|
|
176
|
+
violationCount: f.violations.length,
|
|
177
|
+
})),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
if (err instanceof SchemaCompatError) {
|
|
183
|
+
logger.warn("console_blueprint_try_schema_compat_rejected", {
|
|
184
|
+
blueprintId,
|
|
185
|
+
findingCount: err.report.findings.length,
|
|
186
|
+
});
|
|
187
|
+
res.status(422).json({
|
|
188
|
+
error: "SCHEMA_MISMATCH_ERROR",
|
|
189
|
+
message: err.message,
|
|
190
|
+
findings: err.report.findings.map((f) => ({
|
|
191
|
+
kind: f.kind,
|
|
192
|
+
specName: f.specName,
|
|
193
|
+
toolName: f.toolName,
|
|
194
|
+
reason: f.reason,
|
|
195
|
+
violationCount: f.violations.length,
|
|
196
|
+
})),
|
|
197
|
+
});
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
throw err;
|
|
201
|
+
}
|
|
202
|
+
try {
|
|
203
|
+
await renderStoreForTry.commit({ render, appId });
|
|
204
|
+
}
|
|
205
|
+
catch (err) {
|
|
206
|
+
logger.warn("console_blueprint_try_commit_failed", {
|
|
207
|
+
blueprintId,
|
|
208
|
+
sessionId,
|
|
209
|
+
error: String(err),
|
|
210
|
+
});
|
|
211
|
+
res.status(500).json({
|
|
212
|
+
error: "commit_failed",
|
|
213
|
+
message: err instanceof Error ? err.message : String(err),
|
|
214
|
+
});
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
// Mint the shortCode last — if earlier steps failed the
|
|
218
|
+
// client never sees a dangling mapping. Best-effort bind
|
|
219
|
+
// to match render.ts's posture (a put failure shouldn't
|
|
220
|
+
// fail the whole try-live — a 500 here would leave the
|
|
221
|
+
// render behind with no way to resolve from
|
|
222
|
+
// `/s/<shortCode>`, but the operator can still hit the
|
|
223
|
+
// render via `/ggui/console/sessions`).
|
|
224
|
+
const shortCode = generateTryLiveShortCode();
|
|
225
|
+
try {
|
|
226
|
+
await shortCodeIndexForTry.put(shortCode, {
|
|
227
|
+
sessionId,
|
|
228
|
+
appId,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
catch (err) {
|
|
232
|
+
logger.warn("console_blueprint_try_shortcode_failed", {
|
|
233
|
+
blueprintId,
|
|
234
|
+
sessionId,
|
|
235
|
+
shortCode,
|
|
236
|
+
error: String(err),
|
|
237
|
+
});
|
|
238
|
+
// Don't fail the response — the client can reopen via
|
|
239
|
+
// the renders list. Surface the issue in the payload
|
|
240
|
+
// so the SPA can show a degraded banner.
|
|
241
|
+
res.status(200).json({
|
|
242
|
+
sessionId,
|
|
243
|
+
shortCode: null,
|
|
244
|
+
url: null,
|
|
245
|
+
warning: "shortCode minted but not persisted; viewer link unavailable. Open via /ggui/console/sessions.",
|
|
246
|
+
});
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
res.json({
|
|
250
|
+
sessionId,
|
|
251
|
+
shortCode,
|
|
252
|
+
url: `/s/${shortCode}`,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
catch (err) {
|
|
256
|
+
logger.warn("console_blueprint_try_failed", {
|
|
257
|
+
blueprintId,
|
|
258
|
+
error: String(err),
|
|
259
|
+
});
|
|
260
|
+
res.status(500).json({
|
|
261
|
+
error: "try_failed",
|
|
262
|
+
message: err instanceof Error ? err.message : String(err),
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
// Partial wiring — /try would attempt a render create that
|
|
269
|
+
// has nowhere to land. Surface with 503 + specific message
|
|
270
|
+
// so the operator knows which seam to add (console cookie +
|
|
271
|
+
// shortCodeIndex live on `console.sessionCookie: true`).
|
|
272
|
+
app.post("/ggui/console/blueprint/:id/try", (_req, res) => {
|
|
273
|
+
applyDevtoolSecurityHeaders(res);
|
|
274
|
+
res.status(503).json({
|
|
275
|
+
error: "try_not_wired",
|
|
276
|
+
message: "POST /ggui/console/blueprint/:id/try requires `renderChannel: true` + `shortCodeIndex` on createGguiServer. The CLI enables both by default via `console.sessionCookie: true`.",
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
app.get("/ggui/console/blueprint/:id", async (req, res) => {
|
|
281
|
+
applyDevtoolSecurityHeaders(res);
|
|
282
|
+
const blueprintId = req.params["id"];
|
|
283
|
+
if (typeof blueprintId !== "string" || blueprintId.length === 0 || blueprintId.length > 256) {
|
|
284
|
+
res.status(400).json({
|
|
285
|
+
error: "invalid_request",
|
|
286
|
+
message: "`id` path parameter must be a non-empty string (≤256 chars)",
|
|
287
|
+
});
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
try {
|
|
291
|
+
const entry = await uiRegistry.get(blueprintId);
|
|
292
|
+
if (!entry) {
|
|
293
|
+
res.status(404).json({
|
|
294
|
+
error: "not_found",
|
|
295
|
+
message: `No blueprint registered with id "${blueprintId}". Check ggui.json#blueprints.include globs + ggui.ui.json#id values.`,
|
|
296
|
+
});
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
const bundle = await uiRegistry.getBundle(blueprintId);
|
|
300
|
+
if (!bundle) {
|
|
301
|
+
res.status(404).json({
|
|
302
|
+
error: "bundle_not_available",
|
|
303
|
+
message: `Blueprint "${blueprintId}" (${entry.manifest.name}) has no bundle available. Either the TSX entry is missing or compile-on-demand failed — check the manifest directory.`,
|
|
304
|
+
});
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
// Same string-materialization rule as the MCP render handler:
|
|
308
|
+
// collapse stream bundles to a plain string so the browser
|
|
309
|
+
// fetch can JSON-parse the response in one shot.
|
|
310
|
+
let code;
|
|
311
|
+
if (typeof bundle.code === "string") {
|
|
312
|
+
code = bundle.code;
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
const reader = bundle.code.getReader();
|
|
316
|
+
const decoder = new TextDecoder();
|
|
317
|
+
let out = "";
|
|
318
|
+
for (;;) {
|
|
319
|
+
const { done, value } = await reader.read();
|
|
320
|
+
if (done)
|
|
321
|
+
break;
|
|
322
|
+
if (typeof value === "string")
|
|
323
|
+
out += value;
|
|
324
|
+
else if (value instanceof Uint8Array)
|
|
325
|
+
out += decoder.decode(value, { stream: true });
|
|
326
|
+
}
|
|
327
|
+
out += decoder.decode();
|
|
328
|
+
code = out;
|
|
329
|
+
}
|
|
330
|
+
res.json({
|
|
331
|
+
blueprintId,
|
|
332
|
+
blueprintName: entry.manifest.name,
|
|
333
|
+
code,
|
|
334
|
+
contentType: bundle.contentType,
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
catch (err) {
|
|
338
|
+
logger.warn("console_blueprint_resolve_failed", {
|
|
339
|
+
blueprintId,
|
|
340
|
+
error: String(err),
|
|
341
|
+
});
|
|
342
|
+
res.status(500).json({
|
|
343
|
+
error: "resolve_failed",
|
|
344
|
+
message: err instanceof Error ? err.message : String(err),
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Console dev-chat round-trip route.
|
|
3
|
+
*
|
|
4
|
+
* POST /ggui/console/chat/message — OSS dev chat round-trip.
|
|
5
|
+
*
|
|
6
|
+
* Routes the message through `ggui_render` whenever the server was
|
|
7
|
+
* composed with a real generator — turning the chat surface into
|
|
8
|
+
* the cohesive agent experience: every user message commits a
|
|
9
|
+
* render against a thread-scoped render; the render handler owns
|
|
10
|
+
* generation, cache, and provisional preview; the client renders
|
|
11
|
+
* the resulting render inline using `GguiSessionRenderer`.
|
|
12
|
+
*
|
|
13
|
+
* Shape: `{ text, threadId?, sessionId? }` →
|
|
14
|
+
* `{ threadId, userMessage, agentMessage, ui? }`.
|
|
15
|
+
* - `ui` is populated only when the render handler is wired AND
|
|
16
|
+
* the call succeeded. `ui.sessionId` is the render id the client
|
|
17
|
+
* subscribes to over `/ws`; the committed render arrives via
|
|
18
|
+
* the subscribe ack's single `render` field, which the client
|
|
19
|
+
* mounts inline to show the agent's generated component.
|
|
20
|
+
* - When the render handler is NOT wired (no `mcpApps`, placeholder
|
|
21
|
+
* mode, or no BYOK), `ui` is absent and `agentMessage.text`
|
|
22
|
+
* carries an honest text-only acknowledgment. This preserves
|
|
23
|
+
* the text-only round-trip path so operators without a key can
|
|
24
|
+
* still exercise the chat UI end-to-end.
|
|
25
|
+
* - `sessionId` is echoed on every response and should be passed
|
|
26
|
+
* back on subsequent messages so the thread reuses one render.
|
|
27
|
+
*
|
|
28
|
+
* Same-origin only — no bearer auth. The console surface is
|
|
29
|
+
* always the operator's own browser pointing at their own `ggui
|
|
30
|
+
* serve` instance; adding bearer auth here would block the
|
|
31
|
+
* dev-page-is-usable claim without meaningful security gain.
|
|
32
|
+
*
|
|
33
|
+
* The render invocation uses `DEFAULT_BUILDER_APP_ID` for tenant
|
|
34
|
+
* scope — same well-known value the `/mcp` endpoint collapses to
|
|
35
|
+
* in OSS single-user mode. Matches blueprint + vector scoping
|
|
36
|
+
* applied by the generator / cache seams.
|
|
37
|
+
*
|
|
38
|
+
* Handler gate: without a generator wired, a render call would
|
|
39
|
+
* allocate a render + shortCode with empty componentCode
|
|
40
|
+
* (codeReady:false) per turn without any visible UI — honest
|
|
41
|
+
* behavior but useless. Falling through to the canned-text path
|
|
42
|
+
* keeps the chat surface usable without a BYOK key AND preserves
|
|
43
|
+
* the exact Lane-1 chat-page spec assertion (`/OSS agent
|
|
44
|
+
* generation/`) without a copy change.
|
|
45
|
+
*/
|
|
46
|
+
import type { SharedHandler } from "@ggui-ai/mcp-server-handlers";
|
|
47
|
+
import type { Express } from "express";
|
|
48
|
+
import type { ZodRawShape } from "zod";
|
|
49
|
+
import type { Logger } from "./logger.js";
|
|
50
|
+
interface MountOptions {
|
|
51
|
+
/** Express app to mount onto. */
|
|
52
|
+
readonly app: Express;
|
|
53
|
+
/**
|
|
54
|
+
* `ggui_render` handler — present only when the composer resolved
|
|
55
|
+
* generation deps (the gate that makes a render turn useful).
|
|
56
|
+
*/
|
|
57
|
+
readonly renderHandler?: SharedHandler<ZodRawShape, ZodRawShape>;
|
|
58
|
+
/** `ggui_handshake` handler paired with the render handler. */
|
|
59
|
+
readonly handshakeHandler?: SharedHandler<ZodRawShape, ZodRawShape>;
|
|
60
|
+
/**
|
|
61
|
+
* Console session-cookie wiring. Present only when the cookie flow
|
|
62
|
+
* is enabled — each successful render turn then mints a same-origin
|
|
63
|
+
* HttpOnly cookie so the chat can open the /ws subscription without
|
|
64
|
+
* a separate POST to /ggui/console/session-cookie.
|
|
65
|
+
*/
|
|
66
|
+
readonly sessionCookie?: {
|
|
67
|
+
readonly secret: string;
|
|
68
|
+
readonly ttlSec?: number;
|
|
69
|
+
readonly secure: boolean;
|
|
70
|
+
};
|
|
71
|
+
/** Structured logger. */
|
|
72
|
+
readonly logger: Logger;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Mount `POST /ggui/console/chat/message` onto the express app.
|
|
76
|
+
* Returns nothing — the route self-registers.
|
|
77
|
+
*/
|
|
78
|
+
export declare function mountConsoleChatRoutes(opts: MountOptions): void;
|
|
79
|
+
export {};
|
|
80
|
+
//# sourceMappingURL=console-chat-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console-chat-routes.d.ts","sourceRoot":"","sources":["../src/console-chat-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,KAAK,CAAC;AAIvC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,UAAU,YAAY;IACpB,iCAAiC;IACjC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACjE,+DAA+D;IAC/D,QAAQ,CAAC,gBAAgB,CAAC,EAAE,aAAa,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACpE;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE;QACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;KAC1B,CAAC;IACF,yBAAyB;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAsJ/D"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Console dev-chat round-trip route.
|
|
3
|
+
*
|
|
4
|
+
* POST /ggui/console/chat/message — OSS dev chat round-trip.
|
|
5
|
+
*
|
|
6
|
+
* Routes the message through `ggui_render` whenever the server was
|
|
7
|
+
* composed with a real generator — turning the chat surface into
|
|
8
|
+
* the cohesive agent experience: every user message commits a
|
|
9
|
+
* render against a thread-scoped render; the render handler owns
|
|
10
|
+
* generation, cache, and provisional preview; the client renders
|
|
11
|
+
* the resulting render inline using `GguiSessionRenderer`.
|
|
12
|
+
*
|
|
13
|
+
* Shape: `{ text, threadId?, sessionId? }` →
|
|
14
|
+
* `{ threadId, userMessage, agentMessage, ui? }`.
|
|
15
|
+
* - `ui` is populated only when the render handler is wired AND
|
|
16
|
+
* the call succeeded. `ui.sessionId` is the render id the client
|
|
17
|
+
* subscribes to over `/ws`; the committed render arrives via
|
|
18
|
+
* the subscribe ack's single `render` field, which the client
|
|
19
|
+
* mounts inline to show the agent's generated component.
|
|
20
|
+
* - When the render handler is NOT wired (no `mcpApps`, placeholder
|
|
21
|
+
* mode, or no BYOK), `ui` is absent and `agentMessage.text`
|
|
22
|
+
* carries an honest text-only acknowledgment. This preserves
|
|
23
|
+
* the text-only round-trip path so operators without a key can
|
|
24
|
+
* still exercise the chat UI end-to-end.
|
|
25
|
+
* - `sessionId` is echoed on every response and should be passed
|
|
26
|
+
* back on subsequent messages so the thread reuses one render.
|
|
27
|
+
*
|
|
28
|
+
* Same-origin only — no bearer auth. The console surface is
|
|
29
|
+
* always the operator's own browser pointing at their own `ggui
|
|
30
|
+
* serve` instance; adding bearer auth here would block the
|
|
31
|
+
* dev-page-is-usable claim without meaningful security gain.
|
|
32
|
+
*
|
|
33
|
+
* The render invocation uses `DEFAULT_BUILDER_APP_ID` for tenant
|
|
34
|
+
* scope — same well-known value the `/mcp` endpoint collapses to
|
|
35
|
+
* in OSS single-user mode. Matches blueprint + vector scoping
|
|
36
|
+
* applied by the generator / cache seams.
|
|
37
|
+
*
|
|
38
|
+
* Handler gate: without a generator wired, a render call would
|
|
39
|
+
* allocate a render + shortCode with empty componentCode
|
|
40
|
+
* (codeReady:false) per turn without any visible UI — honest
|
|
41
|
+
* behavior but useless. Falling through to the canned-text path
|
|
42
|
+
* keeps the chat surface usable without a BYOK key AND preserves
|
|
43
|
+
* the exact Lane-1 chat-page spec assertion (`/OSS agent
|
|
44
|
+
* generation/`) without a copy change.
|
|
45
|
+
*/
|
|
46
|
+
import { randomUUID } from "node:crypto";
|
|
47
|
+
import { DEFAULT_BUILDER_APP_ID } from "./auth.js";
|
|
48
|
+
import { mintDevtoolCookie } from "./console-auth.js";
|
|
49
|
+
import { applyDevtoolSecurityHeaders } from "./console-headers.js";
|
|
50
|
+
/**
|
|
51
|
+
* Mount `POST /ggui/console/chat/message` onto the express app.
|
|
52
|
+
* Returns nothing — the route self-registers.
|
|
53
|
+
*/
|
|
54
|
+
export function mountConsoleChatRoutes(opts) {
|
|
55
|
+
const { app, renderHandler, handshakeHandler, sessionCookie, logger } = opts;
|
|
56
|
+
app.post("/ggui/console/chat/message", async (req, res) => {
|
|
57
|
+
applyDevtoolSecurityHeaders(res);
|
|
58
|
+
const body = (req.body ?? {});
|
|
59
|
+
const text = typeof body.text === "string" ? body.text.trim() : "";
|
|
60
|
+
if (text.length === 0) {
|
|
61
|
+
res.status(400).json({
|
|
62
|
+
error: "invalid_request",
|
|
63
|
+
message: "`text` (non-empty string) is required",
|
|
64
|
+
});
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (text.length > 4000) {
|
|
68
|
+
res.status(400).json({
|
|
69
|
+
error: "invalid_request",
|
|
70
|
+
message: "`text` must be <= 4000 chars",
|
|
71
|
+
});
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const threadId = typeof body.threadId === "string" && body.threadId.length > 0
|
|
75
|
+
? body.threadId
|
|
76
|
+
: `chat-${randomUUID()}`;
|
|
77
|
+
const now = Date.now();
|
|
78
|
+
const userMessage = {
|
|
79
|
+
id: `msg-${randomUUID()}`,
|
|
80
|
+
role: "user",
|
|
81
|
+
text,
|
|
82
|
+
createdAt: now,
|
|
83
|
+
};
|
|
84
|
+
// Attempt real generation through `ggui_render` when wired.
|
|
85
|
+
// `renderHandler` is undefined when mcpApps was disabled or
|
|
86
|
+
// the operator built a custom handler set without render. The
|
|
87
|
+
// handler itself returns `codeReady:false` when generation deps
|
|
88
|
+
// aren't wired (no BYOK) — we surface that honestly on the
|
|
89
|
+
// agentMessage text without pretending a UI landed.
|
|
90
|
+
let ui;
|
|
91
|
+
let agentText;
|
|
92
|
+
if (renderHandler && handshakeHandler) {
|
|
93
|
+
try {
|
|
94
|
+
const requestId = randomUUID();
|
|
95
|
+
const handshakeInput = {
|
|
96
|
+
story: { intent: text, contract: {} },
|
|
97
|
+
};
|
|
98
|
+
const hsRaw = await handshakeHandler.handler(handshakeInput, {
|
|
99
|
+
appId: DEFAULT_BUILDER_APP_ID,
|
|
100
|
+
requestId,
|
|
101
|
+
});
|
|
102
|
+
const handshakeId = hsRaw.handshakeId;
|
|
103
|
+
const raw = await renderHandler.handler({ handshakeId, contract: {} }, { appId: DEFAULT_BUILDER_APP_ID, requestId });
|
|
104
|
+
const result = raw;
|
|
105
|
+
ui = {
|
|
106
|
+
sessionId: result.sessionId,
|
|
107
|
+
shortCode: result.shortCode,
|
|
108
|
+
codeReady: result.codeReady,
|
|
109
|
+
...(result.cache ? { cache: result.cache } : {}),
|
|
110
|
+
};
|
|
111
|
+
// If console cookie auth is enabled, mint a session
|
|
112
|
+
// cookie so the chat can open the /ws subscription without
|
|
113
|
+
// a separate POST to /ggui/console/session-cookie. Single round-trip
|
|
114
|
+
// per turn; cookie is same-origin HttpOnly.
|
|
115
|
+
if (sessionCookie) {
|
|
116
|
+
const mint = mintDevtoolCookie({
|
|
117
|
+
sessionId: result.sessionId,
|
|
118
|
+
appId: DEFAULT_BUILDER_APP_ID,
|
|
119
|
+
secret: sessionCookie.secret,
|
|
120
|
+
...(sessionCookie.ttlSec !== undefined ? { ttlSec: sessionCookie.ttlSec } : {}),
|
|
121
|
+
secure: sessionCookie.secure,
|
|
122
|
+
});
|
|
123
|
+
res.setHeader("Set-Cookie", mint.setCookieHeader);
|
|
124
|
+
}
|
|
125
|
+
if (result.codeReady) {
|
|
126
|
+
agentText = result.cache?.hit
|
|
127
|
+
? "Reused a matching UI from cache for your request."
|
|
128
|
+
: "Generated a UI for your request.";
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
// Generator ran but produced no code (no BYOK, generator
|
|
132
|
+
// error, or placeholder mode). Honest text so the
|
|
133
|
+
// operator knows why the surface didn't render a UI.
|
|
134
|
+
agentText =
|
|
135
|
+
"I received your message, but generation did not produce a UI " +
|
|
136
|
+
"(no BYOK key configured, or the provider declined). Export " +
|
|
137
|
+
"ANTHROPIC_API_KEY / OPENAI_API_KEY / GOOGLE_API_KEY / " +
|
|
138
|
+
"OPENROUTER_API_KEY and retry.";
|
|
139
|
+
// Drop the ui payload — no code ready means nothing to
|
|
140
|
+
// render inline. The agent text carries the diagnosis.
|
|
141
|
+
ui = undefined;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
logger.warn?.("console_chat_render_failed", {
|
|
146
|
+
threadId,
|
|
147
|
+
error: err instanceof Error ? err.message : String(err),
|
|
148
|
+
});
|
|
149
|
+
agentText =
|
|
150
|
+
"Generation failed: " +
|
|
151
|
+
(err instanceof Error ? err.message : String(err)) +
|
|
152
|
+
". The chat surface is still live — retry or try a different prompt.";
|
|
153
|
+
ui = undefined;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const agentMessage = {
|
|
157
|
+
id: `msg-${randomUUID()}`,
|
|
158
|
+
role: "agent",
|
|
159
|
+
text: agentText ??
|
|
160
|
+
// No render handler at all — text-only fallback. Keeps the
|
|
161
|
+
// Lane-1 chat-page spec green by preserving the exact copy
|
|
162
|
+
// it asserts against.
|
|
163
|
+
"Message received. OSS agent generation is not yet wired — " +
|
|
164
|
+
"this is the text-only dev chat. Full responses " +
|
|
165
|
+
"and generated UIs arrive once the generator port lands.",
|
|
166
|
+
createdAt: now + 1,
|
|
167
|
+
};
|
|
168
|
+
logger.debug?.("console_chat_message", {
|
|
169
|
+
threadId,
|
|
170
|
+
userMessageId: userMessage.id,
|
|
171
|
+
textLength: text.length,
|
|
172
|
+
uiSessionId: ui?.sessionId,
|
|
173
|
+
uiCodeReady: ui?.codeReady,
|
|
174
|
+
});
|
|
175
|
+
res.status(200).json({
|
|
176
|
+
threadId,
|
|
177
|
+
userMessage,
|
|
178
|
+
agentMessage,
|
|
179
|
+
...(ui ? { ui } : {}),
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Console manifest-read route.
|
|
3
|
+
*
|
|
4
|
+
* GET /ggui/console/config — VSCode-settings-style read of the
|
|
5
|
+
* resolved `ggui.json`. Returns the parsed manifest, the raw
|
|
6
|
+
* file contents for display, and the introspected v1 JSON Schema
|
|
7
|
+
* (which carries field descriptions via the `.describe()` calls
|
|
8
|
+
* on `GguiJsonV1`).
|
|
9
|
+
*
|
|
10
|
+
* Source resolution: walks up from `process.cwd()` to find the
|
|
11
|
+
* nearest `ggui.json`. Honest about three states:
|
|
12
|
+
* - found + valid → `{source: {found:true, path}, manifest, raw, schema}`
|
|
13
|
+
* - found + invalid → `{source: {found:true, path, error: {message}},
|
|
14
|
+
* raw, schema}` (no manifest field — the operator inspects the raw
|
|
15
|
+
* bytes + sees the validation error so they can fix the file)
|
|
16
|
+
* - not found → `{source: {found:false, searchedFrom}, schema}`
|
|
17
|
+
* (the schema still ships so operators can browse what would be
|
|
18
|
+
* configurable IF a manifest existed)
|
|
19
|
+
*
|
|
20
|
+
* Read-only. Form controls on the same payload and a PATCH
|
|
21
|
+
* endpoint with atomic write + conflict detection layer on top.
|
|
22
|
+
*/
|
|
23
|
+
import type { Express } from "express";
|
|
24
|
+
import type { Logger } from "./logger.js";
|
|
25
|
+
interface MountOptions {
|
|
26
|
+
/** Express app to mount onto. */
|
|
27
|
+
readonly app: Express;
|
|
28
|
+
/** Structured logger for read/conversion warnings. */
|
|
29
|
+
readonly logger: Logger;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Mount `GET /ggui/console/config` onto the express app. Returns
|
|
33
|
+
* nothing — the route self-registers.
|
|
34
|
+
*/
|
|
35
|
+
export declare function mountConsoleConfigRoutes(opts: MountOptions): void;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=console-config-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console-config-routes.d.ts","sourceRoot":"","sources":["../src/console-config-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAIvC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,UAAU,YAAY;IACpB,iCAAiC;IACjC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,sDAAsD;IACtD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CA0DjE"}
|