feat(custom-widgets): complete Custom JSX v2 (#6390)
This commit is contained in:
1 parent
3a1245cbc5
commit
acdfcbb18e
416 files changed
+37853
-18066
No files matched your search
@@ -2,36 +2,39 @@ import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { permissionRequiredProcedure } from "../../trpc";
|
||||
import { previewSessionRequestSchema, recordPreviewJournal } from "./preview-procedure-helpers";
|
||||
import { executeCustomWidgetRequest } from "./request-executor";
|
||||
import { hashRuntimeParams, renderRequestTarget } from "./request-manifest";
|
||||
import { acquireCustomWidgetRequestLimit } from "./request-limits";
|
||||
import {
|
||||
getPreviewJournal,
|
||||
getPreviewSession,
|
||||
getPreviewSessionSecrets,
|
||||
setPreviewSessionLiveActions,
|
||||
} from "./preview-sessions";
|
||||
getPreviewRequestSource,
|
||||
previewSessionRequestSchema,
|
||||
recordPreviewJournal,
|
||||
resolvePreviewRequestParams,
|
||||
} from "./preview-procedure-helpers";
|
||||
import { executeCustomWidgetRequest } from "./request-executor";
|
||||
import { hashRuntimeParams, renderRequestBody, renderRequestTarget } from "./request-manifest";
|
||||
import { acquireCustomWidgetRequestLimit } from "./request-limits";
|
||||
import { getPreviewJournal, getPreviewSession, setPreviewSessionLiveActions } from "./preview-sessions";
|
||||
|
||||
const adminProcedure = permissionRequiredProcedure.requiresPermission("admin");
|
||||
const manageProcedure = permissionRequiredProcedure.requiresPermission("custom-widget-manage");
|
||||
|
||||
export const previewQueryProcedures = {
|
||||
previewQuery: adminProcedure
|
||||
previewQuery: manageProcedure
|
||||
.meta({
|
||||
mcp: {
|
||||
enabled: true,
|
||||
description:
|
||||
"Run one named GET query from a short-lived custom-widget preview session. REQUIRED: sessionId from customWidget_preview, requestId declared as a query, and typed params. Uses the hardened executor and returns sanitized response data for another validate/update iteration.",
|
||||
description: "Run one named query from a short-lived custom widget preview session.",
|
||||
},
|
||||
})
|
||||
.input(previewSessionRequestSchema)
|
||||
.query(async ({ ctx, input }) => {
|
||||
const session = await getPreviewSession(input.sessionId, ctx.session.user.id);
|
||||
const request = session.requests.find(
|
||||
(candidate) => candidate.id === input.requestId && candidate.kind === "query",
|
||||
);
|
||||
if (!request) throw new TRPCError({ code: "NOT_FOUND", message: "Preview query was not found" });
|
||||
const targetUrl = renderRequestTarget(session.baseUrl, request, input.params);
|
||||
const definition = session.requests[input.requestId];
|
||||
if (definition?.kind !== "query")
|
||||
throw new TRPCError({ code: "NOT_FOUND", message: "Preview query was not found" });
|
||||
const request = { id: input.requestId, ...definition };
|
||||
const resolved = getPreviewRequestSource(session, request.source);
|
||||
if (!resolved) throw new TRPCError({ code: "NOT_FOUND", message: "Preview source was not found" });
|
||||
const params = resolvePreviewRequestParams(request, session.options, input.params);
|
||||
const targetUrl = renderRequestTarget(resolved.source.baseUrl, request, params);
|
||||
const body = renderRequestBody(request, params);
|
||||
const release = await acquireCustomWidgetRequestLimit({
|
||||
category: "query",
|
||||
userId: ctx.session.user.id,
|
||||
@@ -41,28 +44,22 @@ export const previewQueryProcedures = {
|
||||
const startedAt = Date.now();
|
||||
try {
|
||||
const response = await executeCustomWidgetRequest({
|
||||
baseUrl: session.baseUrl,
|
||||
baseUrl: resolved.source.baseUrl,
|
||||
targetUrl,
|
||||
method: "GET",
|
||||
staticHeaders: request.staticHeaders,
|
||||
auth:
|
||||
request.auth === "none"
|
||||
? undefined
|
||||
: {
|
||||
type: session.authType,
|
||||
secrets: getPreviewSessionSecrets(session),
|
||||
headerName: session.headerName,
|
||||
},
|
||||
networkScope: session.networkScope,
|
||||
method: request.method,
|
||||
body,
|
||||
staticHeaders: request.headers,
|
||||
auth: request.auth === "none" ? undefined : resolved.auth,
|
||||
networkScope: resolved.source.networkScope,
|
||||
kind: "query",
|
||||
cacheKey: `custom-jsx:preview:${session.id}:${request.id}:${hashRuntimeParams(input.params)}`,
|
||||
cacheTtlSeconds: request.cacheTtlSeconds,
|
||||
cacheKey: `custom-jsx:preview:${session.id}:${request.id}:${hashRuntimeParams(params)}`,
|
||||
cacheTtlSeconds: request.cacheSeconds,
|
||||
});
|
||||
await recordPreviewJournal(session, {
|
||||
requestId: request.id,
|
||||
kind: "query",
|
||||
method: "GET",
|
||||
pathTemplate: request.pathTemplate,
|
||||
method: request.method,
|
||||
path: request.path,
|
||||
status: response.status,
|
||||
durationMs: Date.now() - startedAt,
|
||||
simulated: false,
|
||||
@@ -79,18 +76,17 @@ export const previewQueryProcedures = {
|
||||
}
|
||||
}),
|
||||
|
||||
setPreviewLiveActions: adminProcedure
|
||||
setPreviewLiveActions: manageProcedure
|
||||
.input(z.object({ sessionId: z.string().min(1), enabled: z.boolean() }))
|
||||
.mutation(async ({ ctx, input }) =>
|
||||
setPreviewSessionLiveActions(input.sessionId, ctx.session.user.id, input.enabled),
|
||||
),
|
||||
|
||||
previewJournal: adminProcedure
|
||||
previewJournal: manageProcedure
|
||||
.meta({
|
||||
mcp: {
|
||||
enabled: true,
|
||||
description:
|
||||
"Read the redacted request journal for a custom-widget preview session. REQUIRED: sessionId. Use it to inspect statuses and durations; credentials and parameter values are never returned.",
|
||||
description: "Read the redacted request journal for a custom widget preview session.",
|
||||
},
|
||||
})
|
||||
.input(z.object({ sessionId: z.string().min(1) }))
|
||||
|
||||
Reference in new issue
Block a user