callman-mcp 0.1.0 → 0.2.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/CHANGELOG.md +82 -0
- package/README.md +45 -16
- package/dist/client/api.d.ts +64 -3
- package/dist/client/api.d.ts.map +1 -1
- package/dist/client/api.js +67 -2
- package/dist/client/api.js.map +1 -1
- package/dist/client/errors.d.ts.map +1 -1
- package/dist/client/errors.js +33 -7
- package/dist/client/errors.js.map +1 -1
- package/dist/client/types.d.ts +91 -2
- package/dist/client/types.d.ts.map +1 -1
- package/dist/context.d.ts +2 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +7 -2
- package/dist/context.js.map +1 -1
- package/dist/domain/contracts.d.ts +893 -0
- package/dist/domain/contracts.d.ts.map +1 -0
- package/dist/domain/contracts.js +90 -0
- package/dist/domain/contracts.js.map +1 -0
- package/dist/domain/diagram/build.d.ts +520 -18
- package/dist/domain/diagram/build.d.ts.map +1 -1
- package/dist/domain/diagram/build.js +65 -19
- package/dist/domain/diagram/build.js.map +1 -1
- package/dist/domain/diagram/patch.d.ts +624 -51
- package/dist/domain/diagram/patch.d.ts.map +1 -1
- package/dist/domain/diagram/patch.js +180 -40
- package/dist/domain/diagram/patch.js.map +1 -1
- package/dist/domain/diagram/style.d.ts +315 -0
- package/dist/domain/diagram/style.d.ts.map +1 -0
- package/dist/domain/diagram/style.js +124 -0
- package/dist/domain/diagram/style.js.map +1 -0
- package/dist/domain/diagram/summarize.d.ts +8 -0
- package/dist/domain/diagram/summarize.d.ts.map +1 -1
- package/dist/domain/diagram/summarize.js +28 -13
- package/dist/domain/diagram/summarize.js.map +1 -1
- package/dist/domain/requestIntegrations.d.ts +719 -0
- package/dist/domain/requestIntegrations.d.ts.map +1 -0
- package/dist/domain/requestIntegrations.js +222 -0
- package/dist/domain/requestIntegrations.js.map +1 -0
- package/dist/domain/requestShape.d.ts +1350 -152
- package/dist/domain/requestShape.d.ts.map +1 -1
- package/dist/domain/requestShape.js +336 -121
- package/dist/domain/requestShape.js.map +1 -1
- package/dist/domain/resolve.d.ts +2 -1
- package/dist/domain/resolve.d.ts.map +1 -1
- package/dist/domain/resolve.js +5 -1
- package/dist/domain/resolve.js.map +1 -1
- package/dist/domain/scenario/build.d.ts +82 -26
- package/dist/domain/scenario/build.d.ts.map +1 -1
- package/dist/domain/scenario/build.js +196 -65
- package/dist/domain/scenario/build.js.map +1 -1
- package/dist/domain/scenario/nodeConfig.d.ts +11 -0
- package/dist/domain/scenario/nodeConfig.d.ts.map +1 -0
- package/dist/domain/scenario/nodeConfig.js +251 -0
- package/dist/domain/scenario/nodeConfig.js.map +1 -0
- package/dist/domain/scenario/summarize.d.ts +145 -25
- package/dist/domain/scenario/summarize.d.ts.map +1 -1
- package/dist/domain/scenario/summarize.js +84 -29
- package/dist/domain/scenario/summarize.js.map +1 -1
- package/dist/lib/mask.d.ts +0 -18
- package/dist/lib/mask.d.ts.map +1 -1
- package/dist/lib/mask.js +2 -44
- package/dist/lib/mask.js.map +1 -1
- package/dist/lib/pagination.d.ts +3 -2
- package/dist/lib/pagination.d.ts.map +1 -1
- package/dist/lib/pagination.js +13 -8
- package/dist/lib/pagination.js.map +1 -1
- package/dist/lib/redact.d.ts +12 -0
- package/dist/lib/redact.d.ts.map +1 -0
- package/dist/lib/redact.js +50 -0
- package/dist/lib/redact.js.map +1 -0
- package/dist/lib/strict.d.ts +4 -0
- package/dist/lib/strict.d.ts.map +1 -0
- package/dist/lib/strict.js +14 -0
- package/dist/lib/strict.js.map +1 -0
- package/dist/prompts/index.js +7 -7
- package/dist/prompts/index.js.map +1 -1
- package/dist/resources/docs/contracts.d.ts +2 -0
- package/dist/resources/docs/contracts.d.ts.map +1 -0
- package/dist/resources/docs/contracts.js +74 -0
- package/dist/resources/docs/contracts.js.map +1 -0
- package/dist/resources/docs/diagramSchema.d.ts +1 -1
- package/dist/resources/docs/diagramSchema.d.ts.map +1 -1
- package/dist/resources/docs/diagramSchema.js +95 -28
- package/dist/resources/docs/diagramSchema.js.map +1 -1
- package/dist/resources/docs/overview.d.ts +1 -1
- package/dist/resources/docs/overview.d.ts.map +1 -1
- package/dist/resources/docs/overview.js +29 -7
- package/dist/resources/docs/overview.js.map +1 -1
- package/dist/resources/docs/requestSchema.d.ts +1 -1
- package/dist/resources/docs/requestSchema.d.ts.map +1 -1
- package/dist/resources/docs/requestSchema.js +85 -16
- package/dist/resources/docs/requestSchema.js.map +1 -1
- package/dist/resources/generated/aiPacks.d.ts +1 -1
- package/dist/resources/generated/aiPacks.d.ts.map +1 -1
- package/dist/resources/generated/aiPacks.js +3 -2
- package/dist/resources/generated/aiPacks.js.map +1 -1
- package/dist/resources/index.d.ts.map +1 -1
- package/dist/resources/index.js +19 -19
- package/dist/resources/index.js.map +1 -1
- package/dist/run/executeCollection.d.ts +3 -1
- package/dist/run/executeCollection.d.ts.map +1 -1
- package/dist/run/executeCollection.js +16 -4
- package/dist/run/executeCollection.js.map +1 -1
- package/dist/run/summarize.d.ts +17 -6
- package/dist/run/summarize.d.ts.map +1 -1
- package/dist/run/summarize.js +48 -41
- package/dist/run/summarize.js.map +1 -1
- package/dist/run/types.d.ts +1 -0
- package/dist/run/types.d.ts.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1 -1
- package/dist/server.js.map +1 -1
- package/dist/tools/catalog.d.ts +1 -1
- package/dist/tools/catalog.d.ts.map +1 -1
- package/dist/tools/catalog.js +18 -0
- package/dist/tools/catalog.js.map +1 -1
- package/dist/tools/collections.d.ts.map +1 -1
- package/dist/tools/collections.js +53 -41
- package/dist/tools/collections.js.map +1 -1
- package/dist/tools/contracts.d.ts +4 -0
- package/dist/tools/contracts.d.ts.map +1 -0
- package/dist/tools/contracts.js +201 -0
- package/dist/tools/contracts.js.map +1 -0
- package/dist/tools/diagrams.d.ts.map +1 -1
- package/dist/tools/diagrams.js +19 -10
- package/dist/tools/diagrams.js.map +1 -1
- package/dist/tools/environments.d.ts.map +1 -1
- package/dist/tools/environments.js +184 -64
- package/dist/tools/environments.js.map +1 -1
- package/dist/tools/import.d.ts.map +1 -1
- package/dist/tools/import.js +111 -20
- package/dist/tools/import.js.map +1 -1
- package/dist/tools/index.d.ts +2 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +19 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/lookups.d.ts +38 -7
- package/dist/tools/lookups.d.ts.map +1 -1
- package/dist/tools/lookups.js +113 -10
- package/dist/tools/lookups.js.map +1 -1
- package/dist/tools/meta.d.ts.map +1 -1
- package/dist/tools/meta.js +9 -4
- package/dist/tools/meta.js.map +1 -1
- package/dist/tools/requests.d.ts.map +1 -1
- package/dist/tools/requests.js +138 -50
- package/dist/tools/requests.js.map +1 -1
- package/dist/tools/run.d.ts.map +1 -1
- package/dist/tools/run.js +84 -28
- package/dist/tools/run.js.map +1 -1
- package/dist/tools/scenarios.d.ts.map +1 -1
- package/dist/tools/scenarios.js +238 -75
- package/dist/tools/scenarios.js.map +1 -1
- package/dist/tools/shared.d.ts +1 -0
- package/dist/tools/shared.d.ts.map +1 -1
- package/dist/tools/shared.js +9 -1
- package/dist/tools/shared.js.map +1 -1
- package/dist/tools/workspaces.d.ts.map +1 -1
- package/dist/tools/workspaces.js +44 -7
- package/dist/tools/workspaces.js.map +1 -1
- package/dist-cjs/client/api.js +67 -2
- package/dist-cjs/client/errors.js +33 -7
- package/dist-cjs/context.js +7 -2
- package/dist-cjs/domain/contracts.js +93 -0
- package/dist-cjs/domain/diagram/build.js +71 -20
- package/dist-cjs/domain/diagram/patch.js +179 -39
- package/dist-cjs/domain/diagram/style.js +130 -0
- package/dist-cjs/domain/diagram/summarize.js +28 -13
- package/dist-cjs/domain/requestIntegrations.js +228 -0
- package/dist-cjs/domain/requestShape.js +342 -121
- package/dist-cjs/domain/resolve.js +5 -1
- package/dist-cjs/domain/scenario/build.js +197 -65
- package/dist-cjs/domain/scenario/nodeConfig.js +260 -0
- package/dist-cjs/domain/scenario/summarize.js +86 -29
- package/dist-cjs/lib/mask.js +3 -48
- package/dist-cjs/lib/pagination.js +13 -8
- package/dist-cjs/lib/redact.js +53 -0
- package/dist-cjs/lib/strict.js +18 -0
- package/dist-cjs/prompts/index.js +7 -7
- package/dist-cjs/resources/docs/contracts.js +76 -0
- package/dist-cjs/resources/docs/diagramSchema.js +95 -28
- package/dist-cjs/resources/docs/overview.js +29 -7
- package/dist-cjs/resources/docs/requestSchema.js +85 -16
- package/dist-cjs/resources/generated/aiPacks.js +3 -2
- package/dist-cjs/resources/index.js +17 -17
- package/dist-cjs/run/executeCollection.js +16 -4
- package/dist-cjs/run/summarize.js +48 -41
- package/dist-cjs/server.js +1 -1
- package/dist-cjs/tools/catalog.js +18 -0
- package/dist-cjs/tools/collections.js +52 -40
- package/dist-cjs/tools/contracts.js +204 -0
- package/dist-cjs/tools/diagrams.js +19 -10
- package/dist-cjs/tools/environments.js +182 -62
- package/dist-cjs/tools/import.js +107 -16
- package/dist-cjs/tools/index.js +21 -2
- package/dist-cjs/tools/lookups.js +123 -11
- package/dist-cjs/tools/meta.js +9 -4
- package/dist-cjs/tools/requests.js +134 -46
- package/dist-cjs/tools/run.js +82 -26
- package/dist-cjs/tools/scenarios.js +235 -72
- package/dist-cjs/tools/shared.js +11 -2
- package/dist-cjs/tools/workspaces.js +43 -6
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requestShape.d.ts","sourceRoot":"","sources":["../../src/domain/requestShape.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"requestShape.d.ts","sourceRoot":"","sources":["../../src/domain/requestShape.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { inferBodyStateFromRaw, toPersistedRequestBody, } from "callman-core";
|
|
1
|
+
import { extractUrlQueryPairs, inferBodyStateFromRaw, stripUrlQuery, toPersistedRequestBody, } from "callman-core";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
3
|
+
import { ToolInputError } from "../client/errors.js";
|
|
4
|
+
import { isMasked, maskHeaderValue, maskSecret } from "../lib/mask.js";
|
|
5
|
+
import { strictObject } from "../lib/strict.js";
|
|
4
6
|
import { clip, jsonPreview, LIMITS, safeStringify } from "../lib/truncate.js";
|
|
7
|
+
import { hasIntegrations, integrationsInputView, requestIntegrationFields, toIntegrationPayload } from "./requestIntegrations.js";
|
|
5
8
|
// The COMPACT request form a model writes (name/method/url, key-value lists,
|
|
6
9
|
// a body that may be a JSON value, a string or a mode object, a small auth
|
|
7
10
|
// object) and its translation into the backend's `POST /requests` payload —
|
|
@@ -9,75 +12,200 @@ import { clip, jsonPreview, LIMITS, safeStringify } from "../lib/truncate.js";
|
|
|
9
12
|
// serialisation (`toPersistedRequestBody`) so an imported request opens in
|
|
10
13
|
// the editor exactly like a hand-made one.
|
|
11
14
|
export const HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS", "TRACE"];
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
// Key/value rows — the backend's own limits (key 1–100 chars, value ≤ 5000),
|
|
16
|
+
// strict so a stray `description` or `type` is an error, not a silent drop.
|
|
17
|
+
export const kvSchema = strictObject({
|
|
18
|
+
key: z.string().trim().min(1).max(100),
|
|
14
19
|
value: z.string().max(5000).default(""),
|
|
15
|
-
enabled: z.boolean().optional(),
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
z.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
z.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
])
|
|
20
|
+
enabled: z.boolean().optional().describe("false keeps the row but does not send it (default true)"),
|
|
21
|
+
}, "row field");
|
|
22
|
+
export const pathVariableSchema = strictObject({
|
|
23
|
+
key: z.string().trim().min(1).max(100).describe("The name after ':' in the URL, without the colon"),
|
|
24
|
+
value: z.string().max(5000).default(""),
|
|
25
|
+
description: z.string().max(5000).optional(),
|
|
26
|
+
}, "path variable field");
|
|
27
|
+
const RAW_LANGUAGES = ["json", "xml", "text", "html"];
|
|
28
|
+
const rawBodySchema = strictObject({
|
|
29
|
+
mode: z.literal("raw"),
|
|
30
|
+
raw: z.string().max(2_000_000).describe("The body text; {{variables}} are resolved when it runs"),
|
|
31
|
+
language: z.enum(RAW_LANGUAGES).optional().describe("Editor language and default Content-Type; sniffed from the text when omitted"),
|
|
32
|
+
rawLanguage: z.enum(RAW_LANGUAGES).optional().describe("Same as language (the stored name)"),
|
|
33
|
+
}, "raw body field");
|
|
34
|
+
const formBodySchema = strictObject({
|
|
35
|
+
mode: z.enum(["formdata", "urlencoded"]),
|
|
36
|
+
entries: z.array(kvSchema).max(200).optional().describe("Text fields; file parts cannot be set through the API"),
|
|
37
|
+
formEntries: z.array(z.object({ key: z.string(), value: z.string().default(""), enabled: z.boolean().optional() }).passthrough()).max(200).optional().describe("Same as entries (the stored name)"),
|
|
38
|
+
}, "form body field");
|
|
39
|
+
const jsonBodySchema = strictObject({ mode: z.literal("json"), json: z.unknown().describe("Any JSON value — use this form when the payload itself has a top-level `mode` key") }, "json body field");
|
|
40
|
+
const noneBodySchema = strictObject({ mode: z.literal("none") }, "body field");
|
|
41
|
+
const BODY_MODES = ["raw", "formdata", "urlencoded", "json", "none"];
|
|
42
|
+
export const bodyInputSchema = z
|
|
43
|
+
.union([
|
|
44
|
+
z.string().max(2_000_000),
|
|
45
|
+
rawBodySchema,
|
|
46
|
+
formBodySchema,
|
|
47
|
+
jsonBodySchema,
|
|
48
|
+
noneBodySchema,
|
|
49
|
+
z.array(z.unknown()),
|
|
50
|
+
z.number(),
|
|
51
|
+
z.boolean(),
|
|
52
|
+
z.record(z.unknown()).refine((value) => !("mode" in value), { message: `A body object with a "mode" key must be one of the modes ${BODY_MODES.join(", ")}` }),
|
|
53
|
+
], {
|
|
54
|
+
errorMap: (issue, ctx) => issue.code === z.ZodIssueCode.invalid_union
|
|
55
|
+
? {
|
|
56
|
+
message: `Invalid body. Send a JSON value (object/array), a string, or { mode: "raw", raw, language? } | { mode: "formdata"|"urlencoded", entries: [{ key, value }] } | { mode: "json", json } | { mode: "none" }.`,
|
|
57
|
+
}
|
|
58
|
+
: { message: ctx.defaultError },
|
|
59
|
+
})
|
|
60
|
+
.describe('A JSON object/array (sent as JSON); a string (JSON is parsed, <xml>/<html> sniffed, otherwise text); { mode: "raw", raw, language: json|xml|text|html }; { mode: "formdata"|"urlencoded", entries: [{ key, value }] }; { mode: "json", json } when the payload itself has a top-level "mode" key; { mode: "none" }.');
|
|
61
|
+
const secret = (what) => z.string().max(10_000).describe(`${what}. {{variable}} references are fine`);
|
|
31
62
|
export const authInputSchema = z.discriminatedUnion("type", [
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
63
|
+
strictObject({ type: z.literal("none") }, "auth field"),
|
|
64
|
+
strictObject({ type: z.literal("bearer"), token: secret("Bearer token") }, "bearer auth field"),
|
|
65
|
+
strictObject({ type: z.literal("basic"), username: z.string().max(5000), password: z.string().max(5000).default("") }, "basic auth field"),
|
|
66
|
+
strictObject({
|
|
36
67
|
type: z.literal("apiKey"),
|
|
37
|
-
key: z.string().max(5000),
|
|
38
|
-
value:
|
|
68
|
+
key: z.string().max(5000).describe("Header or query parameter name, e.g. X-API-Key"),
|
|
69
|
+
value: secret("API key"),
|
|
39
70
|
location: z.enum(["header", "query"]).default("header"),
|
|
40
|
-
}),
|
|
41
|
-
|
|
71
|
+
}, "apiKey auth field"),
|
|
72
|
+
strictObject({
|
|
42
73
|
type: z.literal("oauth2"),
|
|
43
74
|
grantType: z.enum(["client_credentials", "password", "refresh_token"]).default("client_credentials"),
|
|
44
75
|
tokenUrl: z.string().max(4096),
|
|
45
76
|
clientId: z.string().max(5000).default(""),
|
|
46
77
|
clientSecret: z.string().max(10_000).default(""),
|
|
47
78
|
scope: z.string().max(5000).default(""),
|
|
48
|
-
username: z.string().max(5000).default(""),
|
|
49
|
-
password: z.string().max(5000).default(""),
|
|
50
|
-
refreshToken: z.string().max(10_000).default(""),
|
|
51
|
-
clientAuth: z.enum(["basic", "body"]).default("body"),
|
|
79
|
+
username: z.string().max(5000).default("").describe("password grant"),
|
|
80
|
+
password: z.string().max(5000).default("").describe("password grant"),
|
|
81
|
+
refreshToken: z.string().max(10_000).default("").describe("refresh_token grant"),
|
|
82
|
+
clientAuth: z.enum(["basic", "body"]).default("body").describe("Send client credentials as a Basic header or in the form body"),
|
|
52
83
|
audience: z.string().max(4096).default(""),
|
|
53
|
-
}),
|
|
84
|
+
}, "oauth2 auth field"),
|
|
54
85
|
]);
|
|
55
|
-
export const requestInputSchema =
|
|
56
|
-
name: z.string().min(1).max(LIMITS.NAME).describe("Display name, e.g. \"GET /users\" or \"Login\""),
|
|
86
|
+
export const requestInputSchema = strictObject({
|
|
87
|
+
name: z.string().trim().min(1).max(LIMITS.NAME).describe("Display name, e.g. \"GET /users\" or \"Login\""),
|
|
57
88
|
method: z.enum(HTTP_METHODS),
|
|
58
89
|
url: z
|
|
59
90
|
.string()
|
|
91
|
+
.trim()
|
|
60
92
|
.min(1)
|
|
61
93
|
.max(4096)
|
|
62
|
-
.describe("Full URL; use {{variable}} for hosts/tokens (e.g. {{baseUrl}}/users/:id) and :name for path variables"),
|
|
94
|
+
.describe("Full URL; use {{variable}} for hosts/tokens (e.g. {{baseUrl}}/users/:id) and :name for path variables. A ?query in the URL becomes `query` rows (they are the same thing — runs send the rows)"),
|
|
63
95
|
headers: z.array(kvSchema).max(200).optional(),
|
|
64
|
-
query: z.array(kvSchema).max(200).optional(),
|
|
65
|
-
pathVariables: z.array(
|
|
66
|
-
body: bodyInputSchema
|
|
67
|
-
.optional()
|
|
68
|
-
.describe("A JSON value (stored as JSON), a string (JSON is parsed, otherwise raw text/xml/html by sniffing), or { mode: \"raw\" | \"formdata\" | \"urlencoded\" | \"none\", … }"),
|
|
96
|
+
query: z.array(kvSchema).max(200).optional().describe("Query parameters; when omitted they are taken from the URL's ?query"),
|
|
97
|
+
pathVariables: z.array(pathVariableSchema).max(200).optional().describe("Values for :name segments in the URL"),
|
|
98
|
+
body: bodyInputSchema.optional(),
|
|
69
99
|
auth: authInputSchema.optional(),
|
|
70
|
-
preRequestScript: z.string().max(100_000).optional(),
|
|
71
|
-
postResponseScript: z.string().max(100_000).optional().describe("pm.* script run after the response (
|
|
72
|
-
testsScript: z.string().max(100_000).optional(),
|
|
73
|
-
folder: z.string().max(
|
|
74
|
-
folderKey: z.string().max(120).optional().describe("
|
|
75
|
-
isEnabledInRunner: z.boolean().optional(),
|
|
76
|
-
|
|
100
|
+
preRequestScript: z.string().max(100_000).optional().describe("pm.* script run before the request (callman://docs/scripting/pm-api)"),
|
|
101
|
+
postResponseScript: z.string().max(100_000).optional().describe("pm.* script run after the response (pm.test, pm.environment.set …)"),
|
|
102
|
+
testsScript: z.string().max(100_000).optional().describe("pm.test(...) assertions run after the response"),
|
|
103
|
+
folder: z.string().max(300).optional().describe("Folder id, name or path (\"Auth/Login\") inside the collection"),
|
|
104
|
+
folderKey: z.string().max(120).optional().describe("create_requests_bulk with collectionName only: key of a folder declared in `folders`"),
|
|
105
|
+
isEnabledInRunner: z.boolean().optional().describe("false = skipped by collection runs (run_collection, the desktop runner, the CLI); default true"),
|
|
106
|
+
...requestIntegrationFields,
|
|
107
|
+
}, "request field");
|
|
77
108
|
export const toRows = (entries) => (entries ?? [])
|
|
78
109
|
.filter((entry) => entry.key.trim().length > 0)
|
|
79
|
-
.map((entry) => ({ key: entry.key.trim(), value: entry.value ?? "", enabled: entry.enabled ?? true }))
|
|
80
|
-
|
|
110
|
+
.map((entry) => ({ key: entry.key.trim(), value: entry.value ?? "", enabled: entry.enabled ?? true }));
|
|
111
|
+
const toPathVariables = (entries) => entries.map((entry) => ({ key: entry.key.trim().replace(/^:/, ""), value: entry.value ?? "", description: entry.description ?? "" }));
|
|
112
|
+
// ── URL ⇄ query rows ───────────────────────────────────────────────────
|
|
113
|
+
// The desktop keeps the URL's ?query and the query rows in sync
|
|
114
|
+
// (request-editor/lib/urlSync.ts), and every runner sends the ROWS — the run
|
|
115
|
+
// bundle strips the URL query. So a query typed into `url` becomes rows, and
|
|
116
|
+
// the stored URL mirrors the enabled rows exactly like the editor does.
|
|
117
|
+
const splitHash = (url) => {
|
|
118
|
+
const index = url.indexOf("#");
|
|
119
|
+
return index === -1 ? { withoutHash: url, hash: "" } : { withoutHash: url.slice(0, index), hash: url.slice(index) };
|
|
120
|
+
};
|
|
121
|
+
export const buildUrlWithQueryRows = (url, rows) => {
|
|
122
|
+
const { withoutHash, hash } = splitHash(url);
|
|
123
|
+
const base = stripUrlQuery(withoutHash);
|
|
124
|
+
const enabled = rows.filter((row) => row.enabled !== false && row.key.trim());
|
|
125
|
+
return enabled.length === 0 ? `${base}${hash}` : `${base}?${enabled.map((row) => `${row.key}=${row.value}`).join("&")}${hash}`;
|
|
126
|
+
};
|
|
127
|
+
export const syncUrlAndQuery = (url, query) => {
|
|
128
|
+
const fromUrl = extractUrlQueryPairs(url).map((pair) => ({ key: pair.key, value: pair.value, enabled: true }));
|
|
129
|
+
if (query === undefined)
|
|
130
|
+
return { url: buildUrlWithQueryRows(url, fromUrl), query: fromUrl, warnings: [] };
|
|
131
|
+
const rows = toRows(query);
|
|
132
|
+
const dropped = fromUrl.filter((pair) => !rows.some((row) => row.key === pair.key));
|
|
133
|
+
return {
|
|
134
|
+
url: buildUrlWithQueryRows(url, rows),
|
|
135
|
+
query: rows,
|
|
136
|
+
warnings: dropped.length > 0 ? [`The URL's query parameter(s) ${dropped.map((pair) => pair.key).join(", ")} were replaced by the \`query\` rows you passed — add them to \`query\` to keep them.`] : [],
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
// ── body ───────────────────────────────────────────────────────────────
|
|
140
|
+
const isModeObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && typeof value.mode === "string";
|
|
141
|
+
// Persisted body — the exact rules of the desktop editor's serializeBodyState
|
|
142
|
+
// (guarded in the desktop by persistedBody.drift.test.ts): JSON stays a bare
|
|
143
|
+
// JSON value; raw xml/text/html persists as { mode, raw, rawLanguage };
|
|
144
|
+
// form bodies keep their entries; empty → null.
|
|
145
|
+
export const toBodyPayload = (body, headers) => {
|
|
146
|
+
if (body === undefined || body === null)
|
|
147
|
+
return null;
|
|
148
|
+
if (typeof body === "string") {
|
|
149
|
+
if (isClipped(body))
|
|
150
|
+
throw clippedError("body");
|
|
151
|
+
return toPersistedRequestBody(inferBodyStateFromRaw(body, headers));
|
|
152
|
+
}
|
|
153
|
+
if (isModeObject(body)) {
|
|
154
|
+
const record = body;
|
|
155
|
+
if (record.mode === "none")
|
|
156
|
+
return null;
|
|
157
|
+
if (record.mode === "json")
|
|
158
|
+
return (record.json ?? null);
|
|
159
|
+
if (record.mode === "raw") {
|
|
160
|
+
const raw = typeof record.raw === "string" ? record.raw : "";
|
|
161
|
+
if (isClipped(raw))
|
|
162
|
+
throw clippedError("body.raw");
|
|
163
|
+
const language = (record.language ?? record.rawLanguage);
|
|
164
|
+
if (language)
|
|
165
|
+
return toPersistedRequestBody({ mode: "raw", raw, rawLanguage: language, formEntries: [] });
|
|
166
|
+
return toPersistedRequestBody(inferBodyStateFromRaw(raw, headers));
|
|
167
|
+
}
|
|
168
|
+
if (record.mode === "formdata" || record.mode === "urlencoded") {
|
|
169
|
+
const persisted = Array.isArray(record.formEntries) ? record.formEntries : null;
|
|
170
|
+
if (persisted?.some((entry) => entry.type === "file")) {
|
|
171
|
+
throw new ToolInputError("FORM_FILE_UNSUPPORTED", "File parts of a form body cannot be set through the API — keep them in the desktop app, or send text fields only.");
|
|
172
|
+
}
|
|
173
|
+
const entries = persisted
|
|
174
|
+
? persisted.map((entry) => ({ key: String(entry.key ?? ""), value: String(entry.value ?? ""), enabled: entry.enabled !== false }))
|
|
175
|
+
: (record.entries ?? []);
|
|
176
|
+
return toPersistedRequestBody({ mode: record.mode, raw: "", formEntries: toRows(entries) });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Any other JSON value is stored as-is (the editor shows it on the JSON tab).
|
|
180
|
+
return body;
|
|
181
|
+
};
|
|
182
|
+
// Previews end in "…" (lib/truncate) — writing one back would store the cut.
|
|
183
|
+
const isClipped = (text) => text.endsWith("…") && text.length >= LIMITS.BODY_PREVIEW;
|
|
184
|
+
const clippedError = (field) => new ToolInputError("CLIPPED_VALUE", `${field} looks like a clipped preview (ends with "…"). Read it with get_request full: true, or pass the complete value.`);
|
|
185
|
+
// The backend (express-mongo-sanitize) rewrites JSON keys that start with "$"
|
|
186
|
+
// or contain "." on ordinary writes — { "$schema": … } is stored as "_schema".
|
|
187
|
+
export const sanitizedKeyWarnings = (body) => {
|
|
188
|
+
const found = new Set();
|
|
189
|
+
const walk = (value, depth) => {
|
|
190
|
+
if (depth > 20 || found.size >= 10 || value === null || typeof value !== "object")
|
|
191
|
+
return;
|
|
192
|
+
if (Array.isArray(value)) {
|
|
193
|
+
for (const item of value)
|
|
194
|
+
walk(item, depth + 1);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
for (const [key, child] of Object.entries(value)) {
|
|
198
|
+
if (key.startsWith("$") || key.includes("."))
|
|
199
|
+
found.add(key);
|
|
200
|
+
walk(child, depth + 1);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
walk(body, 0);
|
|
204
|
+
return found.size > 0
|
|
205
|
+
? [`The server rewrites JSON keys that start with "$" or contain "." (${[...found].join(", ")} → "_"). Keep such payloads as a raw string body ({ mode: "raw", raw: "…", language: "json" }).`]
|
|
206
|
+
: [];
|
|
207
|
+
};
|
|
208
|
+
// ── auth ───────────────────────────────────────────────────────────────
|
|
81
209
|
const EMPTY_AUTH = {
|
|
82
210
|
type: "none",
|
|
83
211
|
bearerToken: "",
|
|
@@ -105,86 +233,141 @@ export const toAuthPayload = (auth) => {
|
|
|
105
233
|
return { ...EMPTY_AUTH };
|
|
106
234
|
}
|
|
107
235
|
};
|
|
108
|
-
|
|
109
|
-
//
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
236
|
+
// Stored auth → the SAME shape authInputSchema accepts, so a read can be
|
|
237
|
+
// written straight back. Secrets are masked unless `reveal`.
|
|
238
|
+
export const authInputView = (auth, reveal = false) => {
|
|
239
|
+
const hide = (value) => (value ? (reveal ? value : maskSecret(value)) : "");
|
|
240
|
+
switch (auth?.type) {
|
|
241
|
+
case "bearer":
|
|
242
|
+
return { type: "bearer", token: hide(auth.bearerToken) };
|
|
243
|
+
case "basic":
|
|
244
|
+
return { type: "basic", username: auth.basicUsername ?? "", password: hide(auth.basicPassword) };
|
|
245
|
+
case "apikey":
|
|
246
|
+
return { type: "apiKey", key: auth.apiKeyKey ?? "", value: hide(auth.apiKeyValue), location: auth.apiKeyLocation ?? "header" };
|
|
247
|
+
case "oauth2": {
|
|
248
|
+
const oauth2 = (auth.oauth2 ?? {});
|
|
249
|
+
return {
|
|
250
|
+
type: "oauth2",
|
|
251
|
+
grantType: oauth2.grantType ?? "client_credentials",
|
|
252
|
+
tokenUrl: oauth2.tokenUrl ?? "",
|
|
253
|
+
clientId: oauth2.clientId ?? "",
|
|
254
|
+
clientSecret: hide(oauth2.clientSecret),
|
|
255
|
+
scope: oauth2.scope ?? "",
|
|
256
|
+
username: oauth2.username ?? "",
|
|
257
|
+
password: hide(oauth2.password),
|
|
258
|
+
refreshToken: hide(oauth2.refreshToken),
|
|
259
|
+
clientAuth: oauth2.clientAuth ?? "body",
|
|
260
|
+
audience: oauth2.audience ?? "",
|
|
261
|
+
};
|
|
130
262
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
263
|
+
default:
|
|
264
|
+
return { type: "none" };
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
// ── masked values ──────────────────────────────────────────────────────
|
|
268
|
+
// get_request shows secrets as ••••ab. Writing that back would store the
|
|
269
|
+
// dots as the credential. On update a masked value that matches the stored
|
|
270
|
+
// secret's mask means "keep the stored value"; anything else masked is refused.
|
|
271
|
+
export const resolveMaskedValues = (item, current) => {
|
|
272
|
+
const problems = [];
|
|
273
|
+
const restoreRows = (field, rows) => rows?.map((row) => {
|
|
274
|
+
if (!isMasked(row.value))
|
|
275
|
+
return row;
|
|
276
|
+
const stored = current?.[field]?.find((entry) => entry.key.toLowerCase() === row.key.toLowerCase());
|
|
277
|
+
if (stored && field === "headers" && maskHeaderValue(stored.key, stored.value) === row.value)
|
|
278
|
+
return { ...row, value: stored.value };
|
|
279
|
+
problems.push(`${field}.${row.key}`);
|
|
280
|
+
return row;
|
|
281
|
+
});
|
|
282
|
+
const out = { ...item, headers: restoreRows("headers", item.headers), query: restoreRows("query", item.query) };
|
|
283
|
+
if (item.headers === undefined)
|
|
284
|
+
delete out.headers;
|
|
285
|
+
if (item.query === undefined)
|
|
286
|
+
delete out.query;
|
|
287
|
+
for (const entry of item.pathVariables ?? [])
|
|
288
|
+
if (isMasked(entry.value))
|
|
289
|
+
problems.push(`pathVariables.${entry.key}`);
|
|
290
|
+
if (item.auth) {
|
|
291
|
+
const storedView = authInputView(current?.auth, true);
|
|
292
|
+
const auth = { ...item.auth };
|
|
293
|
+
for (const [key, value] of Object.entries(auth)) {
|
|
294
|
+
if (!isMasked(value))
|
|
295
|
+
continue;
|
|
296
|
+
const stored = storedView.type === auth.type ? storedView[key] : undefined;
|
|
297
|
+
if (typeof stored === "string" && stored && maskSecret(stored) === value)
|
|
298
|
+
auth[key] = stored;
|
|
299
|
+
else
|
|
300
|
+
problems.push(`auth.${key}`);
|
|
134
301
|
}
|
|
302
|
+
out.auth = auth;
|
|
135
303
|
}
|
|
136
|
-
|
|
137
|
-
|
|
304
|
+
if (problems.length > 0) {
|
|
305
|
+
throw new ToolInputError("MASKED_VALUE", `Masked values (••••) cannot be saved: ${problems.join(", ")}. Pass the real value or a {{variable}}, or leave the field out to keep what is stored (get_request reveal: true shows it).`, { fields: problems });
|
|
306
|
+
}
|
|
307
|
+
return out;
|
|
138
308
|
};
|
|
139
|
-
|
|
309
|
+
const noConnections = (_ref, _type, where) => {
|
|
310
|
+
throw new ToolInputError("CONNECTIONS_UNAVAILABLE", `${where}: connections were not loaded for this call.`);
|
|
311
|
+
};
|
|
312
|
+
export const toCreateRequestPayload = (item, target, resolve = noConnections) => {
|
|
140
313
|
const headers = toRows(item.headers);
|
|
314
|
+
const { url, query, warnings } = syncUrlAndQuery(item.url.trim(), item.query);
|
|
315
|
+
const body = toBodyPayload(item.body, headers);
|
|
141
316
|
return {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
.
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
317
|
+
payload: {
|
|
318
|
+
name: item.name.trim().slice(0, LIMITS.NAME),
|
|
319
|
+
method: item.method,
|
|
320
|
+
url,
|
|
321
|
+
headers,
|
|
322
|
+
query,
|
|
323
|
+
pathVariables: toPathVariables(item.pathVariables ?? []),
|
|
324
|
+
body,
|
|
325
|
+
auth: toAuthPayload(item.auth),
|
|
326
|
+
preRequestScript: item.preRequestScript ?? "",
|
|
327
|
+
postResponseScript: item.postResponseScript ?? "",
|
|
328
|
+
testsScript: item.testsScript ?? "",
|
|
329
|
+
...(hasIntegrations(item) ? toIntegrationPayload(item, resolve) : {}),
|
|
330
|
+
collectionId: target.collectionId,
|
|
331
|
+
folderId: target.folderId,
|
|
332
|
+
},
|
|
333
|
+
warnings: [...warnings, ...sanitizedKeyWarnings(body)],
|
|
157
334
|
};
|
|
158
335
|
};
|
|
159
336
|
// `format: "requests"` bulk import row — same document minus the ids the
|
|
160
|
-
// server assigns, plus the payload-local folderKey.
|
|
161
|
-
|
|
162
|
-
|
|
337
|
+
// server assigns, plus the payload-local folderKey. The import route is not
|
|
338
|
+
// key-sanitized, so no "$" warning here.
|
|
339
|
+
export const toFlatImportRequest = (item, resolve = noConnections) => {
|
|
340
|
+
const { collectionId: _c, folderId: _f, ...payload } = toCreateRequestPayload(item, { collectionId: "", folderId: null }, resolve).payload;
|
|
163
341
|
return { ...payload, ...(item.folderKey ? { folderKey: item.folderKey } : {}) };
|
|
164
342
|
};
|
|
165
|
-
export const updateRequestInputSchema =
|
|
166
|
-
.
|
|
167
|
-
.
|
|
168
|
-
|
|
169
|
-
|
|
343
|
+
export const updateRequestInputSchema = strictObject({
|
|
344
|
+
...Object.fromEntries(Object.entries(requestInputSchema.shape).filter(([key]) => key !== "folderKey").map(([key, schema]) => [key, schema.optional()])),
|
|
345
|
+
collection: z.string().max(200).optional().describe("Narrows a request NAME lookup to one collection (it does not move the request — use move_requests)"),
|
|
346
|
+
}, "request field");
|
|
347
|
+
// Only the fields passed change. isEnabledInRunner is NOT part of the PATCH
|
|
348
|
+
// (the backend's update schema strips it) — the caller sends it to the
|
|
349
|
+
// run-toggle endpoint.
|
|
350
|
+
export const toUpdateRequestPayload = (item, current, target, resolve = noConnections) => {
|
|
170
351
|
const out = {};
|
|
352
|
+
const warnings = [];
|
|
171
353
|
if (item.name !== undefined)
|
|
172
354
|
out.name = item.name.trim().slice(0, LIMITS.NAME);
|
|
173
355
|
if (item.method !== undefined)
|
|
174
356
|
out.method = item.method;
|
|
175
|
-
if (item.url !== undefined)
|
|
176
|
-
|
|
357
|
+
if (item.url !== undefined || item.query !== undefined) {
|
|
358
|
+
const synced = syncUrlAndQuery((item.url ?? current.url).trim(), item.query ?? (item.url !== undefined ? undefined : current.query ?? []));
|
|
359
|
+
out.url = synced.url;
|
|
360
|
+
out.query = synced.query;
|
|
361
|
+
warnings.push(...synced.warnings);
|
|
362
|
+
}
|
|
177
363
|
if (item.headers !== undefined)
|
|
178
364
|
out.headers = toRows(item.headers);
|
|
179
|
-
if (item.
|
|
180
|
-
out.
|
|
181
|
-
if (item.
|
|
182
|
-
out.
|
|
183
|
-
|
|
184
|
-
.map((entry) => ({ key: entry.key.trim(), value: entry.value ?? "", description: entry.description ?? "" }));
|
|
365
|
+
if (item.pathVariables !== undefined)
|
|
366
|
+
out.pathVariables = toPathVariables(item.pathVariables);
|
|
367
|
+
if (item.body !== undefined) {
|
|
368
|
+
out.body = toBodyPayload(item.body, item.headers !== undefined ? toRows(item.headers) : (current.headers ?? []));
|
|
369
|
+
warnings.push(...sanitizedKeyWarnings(out.body));
|
|
185
370
|
}
|
|
186
|
-
if (item.body !== undefined)
|
|
187
|
-
out.body = toBodyPayload(item.body, toRows(item.headers));
|
|
188
371
|
if (item.auth !== undefined)
|
|
189
372
|
out.auth = toAuthPayload(item.auth);
|
|
190
373
|
if (item.preRequestScript !== undefined)
|
|
@@ -193,13 +376,11 @@ export const toUpdateRequestPayload = (item, target) => {
|
|
|
193
376
|
out.postResponseScript = item.postResponseScript;
|
|
194
377
|
if (item.testsScript !== undefined)
|
|
195
378
|
out.testsScript = item.testsScript;
|
|
196
|
-
if (item
|
|
197
|
-
out
|
|
198
|
-
if (target.collectionId !== undefined)
|
|
199
|
-
out.collectionId = target.collectionId;
|
|
379
|
+
if (hasIntegrations(item))
|
|
380
|
+
Object.assign(out, toIntegrationPayload(item, resolve, current));
|
|
200
381
|
if (target.folderId !== undefined)
|
|
201
382
|
out.folderId = target.folderId;
|
|
202
|
-
return out;
|
|
383
|
+
return { payload: out, warnings };
|
|
203
384
|
};
|
|
204
385
|
// ── outbound views ─────────────────────────────────────────────────────
|
|
205
386
|
const kvView = (rows, maskHeaders) => (rows ?? []).map((row) => ({
|
|
@@ -207,9 +388,35 @@ const kvView = (rows, maskHeaders) => (rows ?? []).map((row) => ({
|
|
|
207
388
|
value: maskHeaders ? maskHeaderValue(row.key, row.value) : row.value,
|
|
208
389
|
...(row.enabled === false ? { enabled: false } : {}),
|
|
209
390
|
}));
|
|
391
|
+
// Stored body → the input shape (a bare JSON value stays bare unless it has
|
|
392
|
+
// a top-level "mode", which would read as a mode object).
|
|
393
|
+
export const bodyInputView = (body) => {
|
|
394
|
+
if (body === null || body === undefined)
|
|
395
|
+
return null;
|
|
396
|
+
if (isModeObject(body)) {
|
|
397
|
+
const record = body;
|
|
398
|
+
if (record.mode === "raw" && typeof record.raw === "string")
|
|
399
|
+
return { mode: "raw", raw: record.raw, language: record.rawLanguage ?? "text" };
|
|
400
|
+
if ((record.mode === "formdata" || record.mode === "urlencoded") && Array.isArray(record.formEntries)) {
|
|
401
|
+
return {
|
|
402
|
+
mode: record.mode,
|
|
403
|
+
entries: record.formEntries.map((entry) => ({
|
|
404
|
+
key: String(entry.key ?? ""),
|
|
405
|
+
value: String(entry.value ?? ""),
|
|
406
|
+
...(entry.enabled === false ? { enabled: false } : {}),
|
|
407
|
+
...(entry.type === "file" ? { file: true } : {}),
|
|
408
|
+
})),
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
return { mode: "json", json: body };
|
|
412
|
+
}
|
|
413
|
+
return body;
|
|
414
|
+
};
|
|
210
415
|
export const compactRequestView = (request, options = {}) => {
|
|
211
|
-
const
|
|
416
|
+
const body = bodyInputView(request.body);
|
|
417
|
+
const bodyText = body === null ? null : safeStringify(body);
|
|
212
418
|
const bodyTruncated = bodyText !== null && !options.full && bodyText.length > LIMITS.BODY_PREVIEW;
|
|
419
|
+
const integrations = integrationsInputView(request);
|
|
213
420
|
return {
|
|
214
421
|
id: request.id,
|
|
215
422
|
name: request.name,
|
|
@@ -220,17 +427,25 @@ export const compactRequestView = (request, options = {}) => {
|
|
|
220
427
|
headers: kvView(request.headers, !options.reveal),
|
|
221
428
|
query: kvView(request.query, false),
|
|
222
429
|
...(request.pathVariables && request.pathVariables.length > 0
|
|
223
|
-
? {
|
|
430
|
+
? {
|
|
431
|
+
pathVariables: request.pathVariables.map((entry) => ({
|
|
432
|
+
key: entry.key,
|
|
433
|
+
value: entry.value ?? "",
|
|
434
|
+
...(entry.description ? { description: entry.description } : {}),
|
|
435
|
+
})),
|
|
436
|
+
}
|
|
224
437
|
: {}),
|
|
225
|
-
body
|
|
226
|
-
|
|
227
|
-
|
|
438
|
+
// A clipped body is never returned as `body` — it would validate as a
|
|
439
|
+
// (cut) body if written back.
|
|
440
|
+
...(bodyTruncated ? { body: null, bodyPreview: jsonPreview(body), bodyTruncated: true } : { body }),
|
|
441
|
+
auth: authInputView(request.auth, options.reveal),
|
|
228
442
|
scripts: {
|
|
229
443
|
preRequest: scriptView(request.preRequestScript, options.full),
|
|
230
444
|
postResponse: scriptView(request.postResponseScript, options.full),
|
|
231
445
|
tests: scriptView(request.testsScript, options.full),
|
|
232
446
|
},
|
|
233
447
|
isEnabledInRunner: request.isEnabledInRunner !== false,
|
|
448
|
+
...(integrations ?? {}),
|
|
234
449
|
updatedAt: request.updatedAt ?? null,
|
|
235
450
|
};
|
|
236
451
|
};
|