@testsmith/api-spector 0.8.9 → 0.9.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.
@@ -1,5 +1,5 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./GraphQLEditor-CR3JSOwU.js","./codemirror-BKmwMUlV.js","./ajv-CJPwFjiP.js","./SoapEditor-eAhSrhoc.js"])))=>i.map(i=>d[i]);
2
- import { r as requireReact, g as getDefaultExportFromCjs, R as React, a as reactExports, b as autocompletion, h as hoverTooltip, j as jsxRuntimeExports, k as keymap, t as toggleComment, D as Decoration, E as EditorView, V as ViewPlugin, c as RangeSetBuilder, x as xml, d as json, e as ReactCodeMirror, o as oneDark, f as javascript } from "./codemirror-BKmwMUlV.js";
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./GraphQLEditor-CmfodipY.js","./codemirror-BKmwMUlV.js","./ajv-CJPwFjiP.js","./SoapEditor-CVRCFvJy.js"])))=>i.map(i=>d[i]);
2
+ import { r as requireReact, g as getDefaultExportFromCjs, R as React, a as reactExports, b as autocompletion, h as hoverTooltip, j as jsxRuntimeExports, V as ViewPlugin, E as EditorView, k as keymap, t as toggleComment, D as Decoration, c as RangeSetBuilder, x as xml, d as json, e as ReactCodeMirror, o as oneDark, f as javascript } from "./codemirror-BKmwMUlV.js";
3
3
  import { r as requireAjv } from "./ajv-CJPwFjiP.js";
4
4
  var client = { exports: {} };
5
5
  var reactDomClient_production = {};
@@ -14979,6 +14979,325 @@ function useActiveEnvironment() {
14979
14979
  [environments, activeEnvironmentId]
14980
14980
  );
14981
14981
  }
14982
+ const FAKER_NS_ALL = ["airline", "animal", "book", "color", "commerce", "company", "database", "datatype", "date", "finance", "food", "git", "hacker", "helpers", "image", "internet", "location", "lorem", "music", "number", "person", "phone", "science", "string", "system", "vehicle", "word"];
14983
+ const FAKER_ALL = {
14984
+ "datatype": [
14985
+ "boolean"
14986
+ ],
14987
+ "date": [
14988
+ "anytime",
14989
+ "between",
14990
+ "betweens",
14991
+ "birthdate",
14992
+ "future",
14993
+ "month",
14994
+ "past",
14995
+ "recent",
14996
+ "soon",
14997
+ "timeZone",
14998
+ "weekday"
14999
+ ],
15000
+ "helpers": [
15001
+ "arrayElement",
15002
+ "arrayElements",
15003
+ "enumValue",
15004
+ "fake",
15005
+ "fromRegExp",
15006
+ "maybe",
15007
+ "multiple",
15008
+ "mustache",
15009
+ "objectEntry",
15010
+ "objectKey",
15011
+ "objectValue",
15012
+ "rangeToNumber",
15013
+ "replaceCreditCardSymbols",
15014
+ "replaceSymbols",
15015
+ "shuffle",
15016
+ "slugify",
15017
+ "uniqueArray",
15018
+ "weightedArrayElement"
15019
+ ],
15020
+ "location": [
15021
+ "buildingNumber",
15022
+ "cardinalDirection",
15023
+ "city",
15024
+ "continent",
15025
+ "country",
15026
+ "countryCode",
15027
+ "county",
15028
+ "direction",
15029
+ "language",
15030
+ "latitude",
15031
+ "longitude",
15032
+ "nearbyGPSCoordinate",
15033
+ "ordinalDirection",
15034
+ "postalAddress",
15035
+ "secondaryAddress",
15036
+ "state",
15037
+ "street",
15038
+ "streetAddress",
15039
+ "timeZone",
15040
+ "zipCode"
15041
+ ],
15042
+ "number": [
15043
+ "bigInt",
15044
+ "binary",
15045
+ "float",
15046
+ "hex",
15047
+ "int",
15048
+ "octal",
15049
+ "romanNumeral"
15050
+ ],
15051
+ "string": [
15052
+ "alpha",
15053
+ "alphanumeric",
15054
+ "binary",
15055
+ "fromCharacters",
15056
+ "hexadecimal",
15057
+ "nanoid",
15058
+ "numeric",
15059
+ "octal",
15060
+ "sample",
15061
+ "symbol",
15062
+ "ulid",
15063
+ "uuid"
15064
+ ],
15065
+ "airline": [
15066
+ "aircraftType",
15067
+ "airline",
15068
+ "airplane",
15069
+ "airport",
15070
+ "flightNumber",
15071
+ "recordLocator",
15072
+ "seat"
15073
+ ],
15074
+ "animal": [
15075
+ "bear",
15076
+ "bird",
15077
+ "cat",
15078
+ "cetacean",
15079
+ "cow",
15080
+ "crocodilia",
15081
+ "dog",
15082
+ "fish",
15083
+ "horse",
15084
+ "insect",
15085
+ "lion",
15086
+ "petName",
15087
+ "rabbit",
15088
+ "rodent",
15089
+ "snake",
15090
+ "type"
15091
+ ],
15092
+ "book": [
15093
+ "author",
15094
+ "format",
15095
+ "genre",
15096
+ "publisher",
15097
+ "series",
15098
+ "title"
15099
+ ],
15100
+ "color": [
15101
+ "cmyk",
15102
+ "colorByCSSColorSpace",
15103
+ "cssSupportedFunction",
15104
+ "cssSupportedSpace",
15105
+ "hsl",
15106
+ "human",
15107
+ "hwb",
15108
+ "lab",
15109
+ "lch",
15110
+ "rgb",
15111
+ "space"
15112
+ ],
15113
+ "commerce": [
15114
+ "department",
15115
+ "isbn",
15116
+ "price",
15117
+ "product",
15118
+ "productAdjective",
15119
+ "productDescription",
15120
+ "productMaterial",
15121
+ "productName",
15122
+ "upc"
15123
+ ],
15124
+ "company": [
15125
+ "buzzAdjective",
15126
+ "buzzNoun",
15127
+ "buzzPhrase",
15128
+ "buzzVerb",
15129
+ "catchPhrase",
15130
+ "catchPhraseAdjective",
15131
+ "catchPhraseDescriptor",
15132
+ "catchPhraseNoun",
15133
+ "name"
15134
+ ],
15135
+ "database": [
15136
+ "collation",
15137
+ "column",
15138
+ "engine",
15139
+ "mongodbObjectId",
15140
+ "type"
15141
+ ],
15142
+ "finance": [
15143
+ "accountName",
15144
+ "accountNumber",
15145
+ "amount",
15146
+ "bic",
15147
+ "bitcoinAddress",
15148
+ "creditCardCVV",
15149
+ "creditCardIssuer",
15150
+ "creditCardNumber",
15151
+ "currency",
15152
+ "currencyCode",
15153
+ "currencyName",
15154
+ "currencyNumericCode",
15155
+ "currencySymbol",
15156
+ "ethereumAddress",
15157
+ "iban",
15158
+ "litecoinAddress",
15159
+ "pin",
15160
+ "routingNumber",
15161
+ "transactionDescription",
15162
+ "transactionType"
15163
+ ],
15164
+ "food": [
15165
+ "adjective",
15166
+ "description",
15167
+ "dish",
15168
+ "ethnicCategory",
15169
+ "fruit",
15170
+ "ingredient",
15171
+ "meat",
15172
+ "spice",
15173
+ "vegetable"
15174
+ ],
15175
+ "git": [
15176
+ "branch",
15177
+ "commitDate",
15178
+ "commitEntry",
15179
+ "commitMessage",
15180
+ "commitSha"
15181
+ ],
15182
+ "hacker": [
15183
+ "abbreviation",
15184
+ "adjective",
15185
+ "ingverb",
15186
+ "noun",
15187
+ "phrase",
15188
+ "verb"
15189
+ ],
15190
+ "image": [
15191
+ "avatar",
15192
+ "avatarGitHub",
15193
+ "dataUri",
15194
+ "personPortrait",
15195
+ "url",
15196
+ "urlLoremFlickr",
15197
+ "urlPicsumPhotos"
15198
+ ],
15199
+ "internet": [
15200
+ "displayName",
15201
+ "domainName",
15202
+ "domainSuffix",
15203
+ "domainWord",
15204
+ "email",
15205
+ "emoji",
15206
+ "exampleEmail",
15207
+ "httpMethod",
15208
+ "httpStatusCode",
15209
+ "ip",
15210
+ "ipv4",
15211
+ "ipv6",
15212
+ "jwt",
15213
+ "jwtAlgorithm",
15214
+ "mac",
15215
+ "password",
15216
+ "port",
15217
+ "protocol",
15218
+ "url",
15219
+ "userAgent",
15220
+ "username"
15221
+ ],
15222
+ "lorem": [
15223
+ "lines",
15224
+ "paragraph",
15225
+ "paragraphs",
15226
+ "sentence",
15227
+ "sentences",
15228
+ "slug",
15229
+ "text",
15230
+ "word",
15231
+ "words"
15232
+ ],
15233
+ "music": [
15234
+ "album",
15235
+ "artist",
15236
+ "genre",
15237
+ "songName"
15238
+ ],
15239
+ "person": [
15240
+ "bio",
15241
+ "firstName",
15242
+ "fullName",
15243
+ "gender",
15244
+ "jobArea",
15245
+ "jobDescriptor",
15246
+ "jobTitle",
15247
+ "jobType",
15248
+ "lastName",
15249
+ "middleName",
15250
+ "prefix",
15251
+ "sex",
15252
+ "sexType",
15253
+ "suffix",
15254
+ "zodiacSign"
15255
+ ],
15256
+ "phone": [
15257
+ "imei",
15258
+ "number"
15259
+ ],
15260
+ "science": [
15261
+ "chemicalElement",
15262
+ "unit"
15263
+ ],
15264
+ "system": [
15265
+ "commonFileExt",
15266
+ "commonFileName",
15267
+ "commonFileType",
15268
+ "cron",
15269
+ "directoryPath",
15270
+ "fileExt",
15271
+ "fileName",
15272
+ "filePath",
15273
+ "fileType",
15274
+ "mimeType",
15275
+ "networkInterface",
15276
+ "semver"
15277
+ ],
15278
+ "vehicle": [
15279
+ "bicycle",
15280
+ "color",
15281
+ "fuel",
15282
+ "manufacturer",
15283
+ "model",
15284
+ "type",
15285
+ "vehicle",
15286
+ "vin",
15287
+ "vrm"
15288
+ ],
15289
+ "word": [
15290
+ "adjective",
15291
+ "adverb",
15292
+ "conjunction",
15293
+ "interjection",
15294
+ "noun",
15295
+ "preposition",
15296
+ "sample",
15297
+ "verb",
15298
+ "words"
15299
+ ]
15300
+ };
14982
15301
  const DYNAMIC_VAR_NAMES = [
14983
15302
  "$uuid",
14984
15303
  "$timestamp",
@@ -15123,23 +15442,23 @@ function chaiChainCompletion(textBefore, pos) {
15123
15442
  const options = (CHAI_AFTER[lastWord] ?? CHAI_DEFAULT).filter((o) => o.label.toLowerCase().includes(partial));
15124
15443
  return { from: pos - m[2].length, options, validFor: /^\w*$/ };
15125
15444
  }
15126
- const FAKER_NAMESPACES = [
15127
- { label: "string", type: "property", info: "String generators" },
15128
- { label: "number", type: "property", info: "Number generators" },
15129
- { label: "person", type: "property", info: "Names, titles, etc." },
15130
- { label: "internet", type: "property", info: "Emails, URLs, IPs, etc." },
15131
- { label: "date", type: "property", info: "Date generators" },
15132
- { label: "lorem", type: "property", info: "Lorem ipsum text" },
15133
- { label: "location", type: "property", info: "Addresses, cities, countries" },
15134
- { label: "finance", type: "property", info: "Credit cards, currency, etc." },
15135
- { label: "color", type: "property", info: "Color values" },
15136
- { label: "company", type: "property", info: "Company names, catch phrases" },
15137
- { label: "commerce", type: "property", info: "Products, prices, departments" },
15138
- { label: "image", type: "property", info: "Image URLs / placeholders" },
15139
- { label: "system", type: "property", info: "File names, MIME types, semver" },
15140
- { label: "helpers", type: "property", info: "Utility helpers (slugify, arrayElement, …)" }
15141
- ];
15142
- const FAKER_SUB = {
15445
+ const CURATED_NS_INFO = {
15446
+ string: "String generators",
15447
+ number: "Number generators",
15448
+ person: "Names, titles, etc.",
15449
+ internet: "Emails, URLs, IPs, etc.",
15450
+ date: "Date generators",
15451
+ lorem: "Lorem ipsum text",
15452
+ location: "Addresses, cities, countries",
15453
+ finance: "Credit cards, currency, etc.",
15454
+ color: "Color values",
15455
+ company: "Company names, catch phrases",
15456
+ commerce: "Products, prices, departments",
15457
+ image: "Image URLs / placeholders",
15458
+ system: "File names, MIME types, semver",
15459
+ helpers: "Utility helpers (slugify, arrayElement, …)"
15460
+ };
15461
+ const CURATED_SUB = {
15143
15462
  string: [
15144
15463
  { label: "uuid", type: "function", detail: "()", info: "Random UUID v4" },
15145
15464
  { label: "alphanumeric", type: "function", detail: "(length)", info: "Random alphanumeric string" },
@@ -15242,6 +15561,18 @@ const FAKER_SUB = {
15242
15561
  { label: "multiple", type: "function", detail: "(fn, {count}?)", info: "Call a generator multiple times" }
15243
15562
  ]
15244
15563
  };
15564
+ const FAKER_NAMESPACES = FAKER_NS_ALL.map((ns) => ({
15565
+ label: ns,
15566
+ type: "property",
15567
+ info: CURATED_NS_INFO[ns] ?? `faker.${ns} generators`
15568
+ }));
15569
+ const FAKER_SUB = Object.fromEntries(
15570
+ FAKER_NS_ALL.map((ns) => {
15571
+ const curated = new Map((CURATED_SUB[ns] ?? []).map((c) => [c.label, c]));
15572
+ const items = (FAKER_ALL[ns] ?? []).map((name) => curated.get(name) ?? { label: name, type: "function", detail: "()" });
15573
+ return [ns, items];
15574
+ })
15575
+ );
15245
15576
  function makeAtCompletionSource(varNames) {
15246
15577
  return function atSource(context) {
15247
15578
  const line = context.state.doc.lineAt(context.pos);
@@ -15859,6 +16190,10 @@ const or$6 = "or";
15859
16190
  const Disabled$6 = "Disabled";
15860
16191
  const en = {
15861
16192
  "Close tab": "Close tab",
16193
+ "Request body": "Request body",
16194
+ "Script editor": "Script editor",
16195
+ "JSON schema": "JSON schema",
16196
+ "Filtered response": "Filtered response",
15862
16197
  Collections: Collections$6,
15863
16198
  History: History$6,
15864
16199
  "Mock servers": "Mock servers",
@@ -24624,7 +24959,7 @@ function parseVarTokens(str) {
24624
24959
  found.push({ name, display });
24625
24960
  }
24626
24961
  };
24627
- for (const m of str.matchAll(/\{\{([^}]+)\}\}/g)) push(m[1].trim(), `{{${m[1].trim()}}}`);
24962
+ for (const m of str.matchAll(/\{\{\s*((?:[^{}]|\{[^{}]*\})+?)\s*\}\}/g)) push(m[1].trim(), `{{${m[1].trim()}}}`);
24628
24963
  for (const m of str.matchAll(/\[([A-Za-z_]\w*)\]/g)) push(m[1], `[${m[1]}]`);
24629
24964
  return found;
24630
24965
  }
@@ -24689,7 +25024,7 @@ function VarInput({ value: value2, onChange, className, wrapperClassName, static
24689
25024
  partialLen.current = from;
24690
25025
  setSuggestions(items);
24691
25026
  setSuggestionMode("var");
24692
- setActiveIndex(-1);
25027
+ setActiveIndex(items.length ? 0 : -1);
24693
25028
  }
24694
25029
  function detectQuery(val, cursor) {
24695
25030
  const before = val.slice(0, cursor);
@@ -24758,9 +25093,12 @@ function VarInput({ value: value2, onChange, className, wrapperClassName, static
24758
25093
  } else if (e.key === "ArrowUp") {
24759
25094
  e.preventDefault();
24760
25095
  setActiveIndex((i) => Math.max(i - 1, -1));
24761
- } else if (e.key === "Enter" && activeIndex >= 0) {
24762
- e.preventDefault();
24763
- apply(suggestions[activeIndex]);
25096
+ } else if (e.key === "Enter") {
25097
+ const idx = activeIndex >= 0 ? activeIndex : suggestionMode === "var" ? 0 : -1;
25098
+ if (idx >= 0 && idx < suggestions.length) {
25099
+ e.preventDefault();
25100
+ apply(suggestions[idx]);
25101
+ }
24764
25102
  } else if (e.key === "Escape") {
24765
25103
  setSuggestions([]);
24766
25104
  }
@@ -24776,9 +25114,10 @@ function VarInput({ value: value2, onChange, className, wrapperClassName, static
24776
25114
  const before = value2.slice(0, cursor);
24777
25115
  const after = value2.slice(cursor);
24778
25116
  const start2 = cursor - partialLen.current;
24779
- const insert = item.insert + (item.close ? "}}" : "");
25117
+ const closeAlready = item.close && after.startsWith("}}");
25118
+ const insert = item.insert + (item.close && !closeAlready ? "}}" : "");
24780
25119
  const newVal = before.slice(0, start2) + insert + after;
24781
- const newCursor = start2 + insert.length;
25120
+ const newCursor = start2 + insert.length + (closeAlready ? 2 : 0);
24782
25121
  onChange(newVal);
24783
25122
  if (item.close) {
24784
25123
  setSuggestions([]);
@@ -24843,6 +25182,298 @@ function VarInput({ value: value2, onChange, className, wrapperClassName, static
24843
25182
  }
24844
25183
  );
24845
25184
  }
25185
+ const SCOPE_HAS_INSTANCES = {
25186
+ request: true,
25187
+ folder: true,
25188
+ collection: true,
25189
+ environment: true,
25190
+ global: false
25191
+ };
25192
+ function colOf(s, id2) {
25193
+ return id2 ? s.collections[id2]?.data : void 0;
25194
+ }
25195
+ function describeLoc(loc) {
25196
+ const s = useStore$1.getState();
25197
+ switch (loc.kind) {
25198
+ case "global":
25199
+ return "globals";
25200
+ case "environment":
25201
+ return `environment "${s.environments[loc.environmentId ?? ""]?.data.name ?? "?"}"`;
25202
+ case "collection":
25203
+ return `collection "${colOf(s, loc.collectionId)?.name ?? "?"}"`;
25204
+ case "folder": {
25205
+ const col = colOf(s, loc.collectionId);
25206
+ const f = col && loc.folderId ? findFolder$1(col.rootFolder, loc.folderId) : null;
25207
+ return `folder "${f?.name ?? "?"}"`;
25208
+ }
25209
+ case "request":
25210
+ return `request "${colOf(s, loc.collectionId)?.requests[loc.requestId ?? ""]?.name ?? "?"}"`;
25211
+ }
25212
+ }
25213
+ function readVarAt(loc, key) {
25214
+ const s = useStore$1.getState();
25215
+ switch (loc.kind) {
25216
+ case "global":
25217
+ return s.globals[key];
25218
+ case "environment":
25219
+ return s.environments[loc.environmentId ?? ""]?.data.variables.find((v) => v.key === key)?.value;
25220
+ case "collection":
25221
+ return colOf(s, loc.collectionId)?.collectionVariables?.[key];
25222
+ case "folder": {
25223
+ const col = colOf(s, loc.collectionId);
25224
+ const f = col && loc.folderId ? findFolder$1(col.rootFolder, loc.folderId) : null;
25225
+ return f?.variables?.[key];
25226
+ }
25227
+ case "request":
25228
+ return colOf(s, loc.collectionId)?.requests[loc.requestId ?? ""]?.variables?.[key];
25229
+ }
25230
+ }
25231
+ function hasVarAt(loc, key) {
25232
+ const s = useStore$1.getState();
25233
+ switch (loc.kind) {
25234
+ case "global":
25235
+ return key in s.globals;
25236
+ case "environment":
25237
+ return !!s.environments[loc.environmentId ?? ""]?.data.variables.some((v) => v.key === key);
25238
+ case "collection":
25239
+ return !!colOf(s, loc.collectionId)?.collectionVariables && key in (colOf(s, loc.collectionId).collectionVariables ?? {});
25240
+ case "folder": {
25241
+ const col = colOf(s, loc.collectionId);
25242
+ const f = col && loc.folderId ? findFolder$1(col.rootFolder, loc.folderId) : null;
25243
+ return !!f?.variables && key in f.variables;
25244
+ }
25245
+ case "request": {
25246
+ const r = colOf(s, loc.collectionId)?.requests[loc.requestId ?? ""];
25247
+ return !!r?.variables && key in r.variables;
25248
+ }
25249
+ }
25250
+ }
25251
+ function isEncryptedEnvSecret(loc, key) {
25252
+ if (loc.kind !== "environment") return false;
25253
+ const v = useStore$1.getState().environments[loc.environmentId ?? ""]?.data.variables.find((x) => x.key === key);
25254
+ return !!(v?.secret && v.secretEncrypted);
25255
+ }
25256
+ function omit(map, key) {
25257
+ const next = { ...map ?? {} };
25258
+ delete next[key];
25259
+ return next;
25260
+ }
25261
+ function addVarAt(loc, key, value2) {
25262
+ const s = useStore$1.getState();
25263
+ switch (loc.kind) {
25264
+ case "global":
25265
+ {
25266
+ const next = { ...s.globals, [key]: value2 };
25267
+ s.setGlobals(next);
25268
+ void window.electron.setGlobals(next);
25269
+ }
25270
+ break;
25271
+ case "environment": {
25272
+ const env2 = s.environments[loc.environmentId ?? ""]?.data;
25273
+ if (!env2) return;
25274
+ s.updateEnvironment(env2.id, { ...env2, variables: [...env2.variables, { key, value: value2, enabled: true }] });
25275
+ break;
25276
+ }
25277
+ case "collection": {
25278
+ const col = colOf(s, loc.collectionId);
25279
+ if (!col) return;
25280
+ s.updateCollectionVariables(col.id, { ...col.collectionVariables ?? {}, [key]: value2 }, col.collectionVariablesDisabled);
25281
+ break;
25282
+ }
25283
+ case "folder": {
25284
+ const col = colOf(s, loc.collectionId);
25285
+ const f = col && loc.folderId ? findFolder$1(col.rootFolder, loc.folderId) : null;
25286
+ if (!col || !f) return;
25287
+ s.updateFolder(col.id, f.id, { variables: { ...f.variables ?? {}, [key]: value2 } });
25288
+ break;
25289
+ }
25290
+ case "request": {
25291
+ const col = colOf(s, loc.collectionId);
25292
+ const r = col?.requests[loc.requestId ?? ""];
25293
+ if (!r) return;
25294
+ s.updateRequest(r.id, { variables: { ...r.variables ?? {}, [key]: value2 } });
25295
+ break;
25296
+ }
25297
+ }
25298
+ }
25299
+ function removeVarAt(loc, key) {
25300
+ const s = useStore$1.getState();
25301
+ switch (loc.kind) {
25302
+ case "global":
25303
+ {
25304
+ const next = omit(s.globals, key);
25305
+ s.setGlobals(next);
25306
+ void window.electron.setGlobals(next);
25307
+ }
25308
+ break;
25309
+ case "environment": {
25310
+ const env2 = s.environments[loc.environmentId ?? ""]?.data;
25311
+ if (!env2) return;
25312
+ s.updateEnvironment(env2.id, { ...env2, variables: env2.variables.filter((v) => v.key !== key) });
25313
+ break;
25314
+ }
25315
+ case "collection": {
25316
+ const col = colOf(s, loc.collectionId);
25317
+ if (!col) return;
25318
+ s.updateCollectionVariables(col.id, omit(col.collectionVariables, key), omit(col.collectionVariablesDisabled, key));
25319
+ break;
25320
+ }
25321
+ case "folder": {
25322
+ const col = colOf(s, loc.collectionId);
25323
+ const f = col && loc.folderId ? findFolder$1(col.rootFolder, loc.folderId) : null;
25324
+ if (!col || !f) return;
25325
+ s.updateFolder(col.id, f.id, { variables: omit(f.variables, key), variablesDisabled: omit(f.variablesDisabled, key) });
25326
+ break;
25327
+ }
25328
+ case "request": {
25329
+ const col = colOf(s, loc.collectionId);
25330
+ const r = col?.requests[loc.requestId ?? ""];
25331
+ if (!r) return;
25332
+ s.updateRequest(r.id, { variables: omit(r.variables, key), variablesDisabled: omit(r.variablesDisabled, key) });
25333
+ break;
25334
+ }
25335
+ }
25336
+ }
25337
+ function moveVariable(src, dst, key) {
25338
+ if (src.kind === dst.kind && src.collectionId === dst.collectionId && src.folderId === dst.folderId && src.requestId === dst.requestId && src.environmentId === dst.environmentId) {
25339
+ return { ok: false, error: "Source and destination are the same." };
25340
+ }
25341
+ if (isEncryptedEnvSecret(src, key)) {
25342
+ return { ok: false, error: `"${key}" is an encrypted secret and can't be moved out of the environment.` };
25343
+ }
25344
+ if (hasVarAt(dst, key)) {
25345
+ return { ok: false, error: `"${key}" already exists in ${describeLoc(dst)}. Rename or remove it there first.` };
25346
+ }
25347
+ const value2 = readVarAt(src, key) ?? "";
25348
+ addVarAt(dst, key, value2);
25349
+ removeVarAt(src, key);
25350
+ return { ok: true };
25351
+ }
25352
+ function walkFolders(col, out, f, path) {
25353
+ for (const sub of f.folders ?? []) {
25354
+ const p = [...path, sub.name];
25355
+ out.push({ loc: { kind: "folder", collectionId: col.id, folderId: sub.id }, label: `${col.name} / ${p.join(" / ")}` });
25356
+ walkFolders(col, out, sub, p);
25357
+ }
25358
+ }
25359
+ function listScopeInstances(kind, exclude) {
25360
+ const s = useStore$1.getState();
25361
+ const out = [];
25362
+ switch (kind) {
25363
+ case "global":
25364
+ out.push({ loc: { kind: "global" }, label: "globals" });
25365
+ break;
25366
+ case "environment":
25367
+ for (const { data } of Object.values(s.environments)) out.push({ loc: { kind: "environment", environmentId: data.id }, label: data.name });
25368
+ break;
25369
+ case "collection":
25370
+ for (const { data } of Object.values(s.collections)) out.push({ loc: { kind: "collection", collectionId: data.id }, label: data.name });
25371
+ break;
25372
+ case "folder":
25373
+ for (const { data } of Object.values(s.collections)) walkFolders(data, out, data.rootFolder, []);
25374
+ break;
25375
+ case "request":
25376
+ for (const { data } of Object.values(s.collections)) {
25377
+ for (const r of Object.values(data.requests)) out.push({ loc: { kind: "request", collectionId: data.id, requestId: r.id }, label: `${data.name} / ${r.name}` });
25378
+ }
25379
+ break;
25380
+ }
25381
+ if (!exclude) return out;
25382
+ const sameLoc = (a) => a.kind === exclude.kind && a.collectionId === exclude.collectionId && a.folderId === exclude.folderId && a.requestId === exclude.requestId && a.environmentId === exclude.environmentId;
25383
+ return out.filter((x) => !sameLoc(x.loc));
25384
+ }
25385
+ const KINDS = ["request", "folder", "collection", "environment", "global"];
25386
+ function MoveVariableMenu({ from, name, onMoved, buttonClassName }) {
25387
+ const t = useT();
25388
+ const [open2, setOpen] = reactExports.useState(false);
25389
+ const [kind, setKind] = reactExports.useState(null);
25390
+ const [error2, setError] = reactExports.useState(null);
25391
+ const scopeWord = {
25392
+ request: t("request"),
25393
+ folder: t("folder"),
25394
+ collection: t("collection"),
25395
+ environment: t("environment"),
25396
+ global: t("globals")
25397
+ };
25398
+ function close() {
25399
+ setOpen(false);
25400
+ setKind(null);
25401
+ setError(null);
25402
+ }
25403
+ function pick(dst) {
25404
+ const res = moveVariable(from, dst, name.trim());
25405
+ if (!res.ok) {
25406
+ setError(res.error ?? t("Move failed"));
25407
+ return;
25408
+ }
25409
+ close();
25410
+ onMoved?.();
25411
+ }
25412
+ function chooseKind(k) {
25413
+ setError(null);
25414
+ const insts = listScopeInstances(k, from);
25415
+ if (insts.length === 0) {
25416
+ setError(t("Nowhere to move it in that scope."));
25417
+ return;
25418
+ }
25419
+ if (insts.length === 1) {
25420
+ pick(insts[0].loc);
25421
+ return;
25422
+ }
25423
+ setKind(k);
25424
+ }
25425
+ const instances = kind ? listScopeInstances(kind, from) : [];
25426
+ const kinds = KINDS.filter((k) => !(k === "global" && from.kind === "global"));
25427
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative inline-block", onClick: (e) => e.stopPropagation(), children: [
25428
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
25429
+ "button",
25430
+ {
25431
+ onClick: () => {
25432
+ setOpen((o) => !o);
25433
+ setKind(null);
25434
+ setError(null);
25435
+ },
25436
+ title: t("Move this variable to another scope"),
25437
+ className: buttonClassName ?? "shrink-0 text-[9px] uppercase tracking-wider text-surface-500 hover:text-blue-400 border border-surface-700 hover:border-blue-500/40 rounded px-1 py-px",
25438
+ children: [
25439
+ t("move"),
25440
+ " ▸"
25441
+ ]
25442
+ }
25443
+ ),
25444
+ open2 && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
25445
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed inset-0 z-40", onClick: close }),
25446
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute right-0 z-50 mt-1 min-w-[190px] max-h-72 overflow-auto bg-surface-800 border border-surface-600 rounded shadow-xl text-xs py-1", children: [
25447
+ error2 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-2 py-1.5 text-[10px] text-red-400 whitespace-normal break-words border-b border-surface-700", children: error2 }),
25448
+ !kind ? kinds.map((k) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
25449
+ "button",
25450
+ {
25451
+ onClick: () => chooseKind(k),
25452
+ className: "w-full text-left px-2 py-1 hover:bg-surface-700 flex items-center justify-between gap-2",
25453
+ children: [
25454
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
25455
+ t("to"),
25456
+ " ",
25457
+ scopeWord[k]
25458
+ ] }),
25459
+ SCOPE_HAS_INSTANCES[k] && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-500", children: "▸" })
25460
+ ]
25461
+ },
25462
+ k
25463
+ )) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
25464
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: () => {
25465
+ setKind(null);
25466
+ setError(null);
25467
+ }, className: "w-full text-left px-2 py-1 text-surface-500 hover:bg-surface-700", children: [
25468
+ "‹ ",
25469
+ t("back")
25470
+ ] }),
25471
+ instances.map((ins, i) => /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => pick(ins.loc), className: "w-full text-left px-2 py-1 hover:bg-surface-700 truncate", title: ins.label, children: ins.label }, i))
25472
+ ] })
25473
+ ] })
25474
+ ] })
25475
+ ] });
25476
+ }
24846
25477
  const HEADER_NAMES = [
24847
25478
  "Accept",
24848
25479
  "Authorization",
@@ -24949,7 +25580,7 @@ const HEADER_VALUE_SUGGESTIONS = {
24949
25580
  function getValueSuggestions(headerName) {
24950
25581
  return HEADER_VALUE_SUGGESTIONS[headerName.toLowerCase()];
24951
25582
  }
24952
- function KVTable({ rows, onChange, keyPlaceholder, valuePlaceholder, headerMode, paramMode }) {
25583
+ function KVTable({ rows, onChange, keyPlaceholder, valuePlaceholder, headerMode, paramMode, moveFrom, onMoved }) {
24953
25584
  const t = useT();
24954
25585
  const keyPh = keyPlaceholder ?? t("Key");
24955
25586
  const valuePh = valuePlaceholder ?? t("Value");
@@ -25082,6 +25713,15 @@ function KVTable({ rows, onChange, keyPlaceholder, valuePlaceholder, headerMode,
25082
25713
  children: "≡"
25083
25714
  }
25084
25715
  ),
25716
+ moveFrom && row.key.trim() && moveFrom(row.key.trim()) && /* @__PURE__ */ jsxRuntimeExports.jsx(
25717
+ MoveVariableMenu,
25718
+ {
25719
+ from: moveFrom(row.key.trim()),
25720
+ name: row.key.trim(),
25721
+ onMoved,
25722
+ buttonClassName: "flex-shrink-0 text-[9px] uppercase tracking-wider text-surface-500 hover:text-blue-400 border border-surface-700 hover:border-blue-500/40 rounded px-1 py-px opacity-0 group-hover:opacity-100 transition-opacity"
25723
+ }
25724
+ ),
25085
25725
  /* @__PURE__ */ jsxRuntimeExports.jsx(
25086
25726
  "button",
25087
25727
  {
@@ -25170,6 +25810,7 @@ function Modal({
25170
25810
  window.addEventListener("mouseup", endDrag);
25171
25811
  }, [offset.x, offset.y, onDragMove, endDrag]);
25172
25812
  reactExports.useEffect(() => endDrag, [endDrag]);
25813
+ const titleId = reactExports.useId();
25173
25814
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
25174
25815
  "div",
25175
25816
  {
@@ -25189,6 +25830,8 @@ function Modal({
25189
25830
  ref: panelRef,
25190
25831
  role: "dialog",
25191
25832
  "aria-modal": "true",
25833
+ "aria-labelledby": title !== void 0 ? titleId : void 0,
25834
+ "aria-label": title === void 0 ? "Dialog" : void 0,
25192
25835
  className: panelClassName,
25193
25836
  style: offset.x || offset.y ? { transform: `translate(${offset.x}px, ${offset.y}px)` } : void 0,
25194
25837
  onMouseDown: onPanelMouseDown,
@@ -25200,10 +25843,10 @@ function Modal({
25200
25843
  className: "flex items-center justify-between px-4 py-2.5 border-b border-surface-800 flex-shrink-0 cursor-move select-none",
25201
25844
  children: [
25202
25845
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
25203
- /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-sm font-semibold", children: title }),
25846
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { id: titleId, className: "text-sm font-semibold", children: title }),
25204
25847
  subtitle !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-surface-400 mt-0.5", children: subtitle })
25205
25848
  ] }),
25206
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "text-surface-400 hover:text-[var(--text-primary)] text-lg leading-none cursor-pointer", children: "×" })
25849
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, "aria-label": "Close", title: "Close", className: "text-surface-400 hover:text-[var(--text-primary)] text-lg leading-none cursor-pointer", children: "×" })
25207
25850
  ]
25208
25851
  }
25209
25852
  ),
@@ -25918,7 +26561,7 @@ function FolderSettingsModal({ collectionId, folder: folder2, onClose }) {
25918
26561
  /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-sm font-semibold", children: t("Folder settings") }),
25919
26562
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-surface-600 mt-0.5", children: t(":name - auth and headers inherited by all requests in this folder", { name: folder2.name }) })
25920
26563
  ] }),
25921
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "text-surface-400 hover:text-white text-lg leading-none", children: "×" })
26564
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, "aria-label": "Close", title: "Close", className: "text-surface-400 hover:text-white text-lg leading-none", children: "×" })
25922
26565
  ] }),
25923
26566
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex border-b border-surface-800 px-4 shrink-0", children: ["auth", "headers"].map((tab) => /* @__PURE__ */ jsxRuntimeExports.jsx(
25924
26567
  "button",
@@ -26013,7 +26656,7 @@ function CollectionSettingsModal({ collection: collection2, onClose }) {
26013
26656
  /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-sm font-semibold", children: t("Collection settings") }),
26014
26657
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-surface-600 mt-0.5", children: t(":name - auth and headers inherited by all requests in this collection", { name: collection2.name }) })
26015
26658
  ] }),
26016
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "text-surface-400 hover:text-white text-lg leading-none", children: "×" })
26659
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, "aria-label": "Close", title: "Close", className: "text-surface-400 hover:text-white text-lg leading-none", children: "×" })
26017
26660
  ] }),
26018
26661
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex border-b border-surface-800 px-4 shrink-0", children: ["auth", "headers", "tls"].map((tab) => /* @__PURE__ */ jsxRuntimeExports.jsx(
26019
26662
  "button",
@@ -26276,7 +26919,7 @@ function SchemaSyncModal({
26276
26919
  children: [
26277
26920
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { "data-modal-drag": true, className: "flex items-center justify-between cursor-move select-none", children: [
26278
26921
  /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-sm font-semibold text-surface-100", children: t("Sync schemas - :name", { name: scopeLabel }) }),
26279
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "text-surface-500 hover:text-surface-300 text-lg leading-none", children: "×" })
26922
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, "aria-label": "Close", title: "Close", className: "text-surface-500 hover:text-surface-300 text-lg leading-none", children: "×" })
26280
26923
  ] }),
26281
26924
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 text-xs", children: [
26282
26925
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-400", children: t(":count operations in spec", { count: specEntries.length }) }),
@@ -26371,7 +27014,7 @@ function SchemaSyncModal({
26371
27014
  children: [
26372
27015
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { "data-modal-drag": true, className: "flex items-center justify-between cursor-move select-none", children: [
26373
27016
  /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-sm font-semibold text-surface-100", children: t("Sync schemas from OpenAPI") }),
26374
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "text-surface-500 hover:text-surface-300 text-lg leading-none", children: "×" })
27017
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, "aria-label": "Close", title: "Close", className: "text-surface-500 hover:text-surface-300 text-lg leading-none", children: "×" })
26375
27018
  ] }),
26376
27019
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-400", children: t("Load an OpenAPI spec to update response schemas on existing requests. Matching uses HTTP method + URL path. Only schemas are touched - URLs, params, headers, auth, and scripts are preserved.") }),
26377
27020
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -27378,7 +28021,6 @@ function RequestRow({
27378
28021
  {
27379
28022
  "data-row": true,
27380
28023
  draggable: true,
27381
- role: "button",
27382
28024
  tabIndex: 0,
27383
28025
  onKeyDown: (e) => {
27384
28026
  if (e.key === "Enter" || e.key === " ") {
@@ -27562,7 +28204,6 @@ function ExampleRow({ name, indent, isActive, reorderable, dragging, dragActive,
27562
28204
  draggable: reorderable && !renaming,
27563
28205
  className: `group/ex flex items-center gap-2 h-[26px] pr-2 rounded-sm cursor-pointer transition-colors outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-blue-400 ${isActive ? "bg-blue-900/40 text-[var(--text-primary)]" : "text-surface-400 hover:bg-surface-800"} ${dragging ? "opacity-40" : ""} ${over ? "ring-1 ring-inset ring-blue-500" : ""}`,
27564
28206
  style: { paddingLeft: indent },
27565
- role: "button",
27566
28207
  tabIndex: 0,
27567
28208
  "aria-label": t("Example: :name", { name }),
27568
28209
  onClick: onOpen,
@@ -28192,7 +28833,6 @@ function CollectionNode({
28192
28833
  {
28193
28834
  "data-row": true,
28194
28835
  className: `group flex items-center gap-1 px-2 py-1.5 cursor-pointer hover:bg-surface-800 transition-colors outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-blue-400 ${panelActive ? "bg-surface-800 text-[var(--text-primary)]" : isActive ? "text-[var(--text-primary)]" : "text-surface-400"} ${col.disabled ? "opacity-50" : ""} ${dropOver ? "outline outline-1 outline-blue-500 rounded" : ""}`,
28195
- role: "button",
28196
28836
  tabIndex: 0,
28197
28837
  onClick: onSelectCollection,
28198
28838
  onDoubleClick: (e) => {
@@ -28372,7 +29012,6 @@ function FolderRow({
28372
29012
  draggable: true,
28373
29013
  className: `group flex items-center gap-1 py-1 transition-colors cursor-pointer outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-blue-400 ${isActive ? "bg-surface-800 text-[var(--text-primary)]" : "text-surface-400 hover:bg-surface-800"} ${folder2.disabled ? "opacity-40" : ""} ${dropInside ? "outline outline-1 outline-blue-500 rounded" : ""}`,
28374
29014
  style: { paddingLeft: indent },
28375
- role: "button",
28376
29015
  tabIndex: 0,
28377
29016
  onClick: () => openFolderPanel(collectionId, folder2.id),
28378
29017
  onDoubleClick: (e) => {
@@ -28853,6 +29492,19 @@ const __vitePreload = function preload(baseModule, deps, importerUrl) {
28853
29492
  return baseModule().catch(handlePreloadError);
28854
29493
  });
28855
29494
  };
29495
+ const scrollerFocusable = ViewPlugin.define((view) => {
29496
+ try {
29497
+ view.scrollDOM.setAttribute("tabindex", "0");
29498
+ } catch {
29499
+ }
29500
+ return {};
29501
+ });
29502
+ function cmLabel(label) {
29503
+ return [
29504
+ EditorView.contentAttributes.of({ "aria-label": label }),
29505
+ scrollerFocusable
29506
+ ];
29507
+ }
28856
29508
  function jsonCommentRanges(input) {
28857
29509
  const ranges = [];
28858
29510
  const n2 = input.length;
@@ -28935,8 +29587,8 @@ function jsonWithComments() {
28935
29587
  function xmlWithComments() {
28936
29588
  return [xml(), commentKeymap];
28937
29589
  }
28938
- const GraphQLEditor = reactExports.lazy(() => __vitePreload(() => import("./GraphQLEditor-CR3JSOwU.js"), true ? __vite__mapDeps([0,1,2]) : void 0, import.meta.url).then((m) => ({ default: m.GraphQLEditor })));
28939
- const SoapEditor = reactExports.lazy(() => __vitePreload(() => import("./SoapEditor-eAhSrhoc.js"), true ? __vite__mapDeps([3,1,2]) : void 0, import.meta.url).then((m) => ({ default: m.SoapEditor })));
29590
+ const GraphQLEditor = reactExports.lazy(() => __vitePreload(() => import("./GraphQLEditor-CmfodipY.js"), true ? __vite__mapDeps([0,1,2]) : void 0, import.meta.url).then((m) => ({ default: m.GraphQLEditor })));
29591
+ const SoapEditor = reactExports.lazy(() => __vitePreload(() => import("./SoapEditor-CVRCFvJy.js"), true ? __vite__mapDeps([3,1,2]) : void 0, import.meta.url).then((m) => ({ default: m.SoapEditor })));
28940
29592
  function BodyTab({ request: request2, onChange }) {
28941
29593
  const t = useT();
28942
29594
  const editorFallback = /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-4 text-xs text-surface-500", children: t("Loading editor…") });
@@ -28992,7 +29644,7 @@ function BodyTab({ request: request2, onChange }) {
28992
29644
  height: "300px",
28993
29645
  maxHeight: "50vh",
28994
29646
  theme: oneDark,
28995
- extensions: [jsonWithComments(), varExt],
29647
+ extensions: [jsonWithComments(), varExt, ...cmLabel(t("Request body"))],
28996
29648
  onChange: (val) => onChange({ body: { ...body, json: val } }),
28997
29649
  basicSetup: { lineNumbers: true, foldGutter: false, autocompletion: false }
28998
29650
  }
@@ -29024,7 +29676,7 @@ function BodyTab({ request: request2, onChange }) {
29024
29676
  height: "300px",
29025
29677
  maxHeight: "50vh",
29026
29678
  theme: oneDark,
29027
- extensions: /xml/i.test(body.rawContentType ?? "") ? [xmlWithComments(), varExt] : [commentKeymap, varExt],
29679
+ extensions: [.../xml/i.test(body.rawContentType ?? "") ? [xmlWithComments(), varExt] : [commentKeymap, varExt], ...cmLabel(t("Request body"))],
29028
29680
  onChange: (val) => onChange({ body: { ...body, raw: val } }),
29029
29681
  basicSetup: { lineNumbers: true, foldGutter: false, autocompletion: false }
29030
29682
  }
@@ -29097,20 +29749,6 @@ const SNIPPET_GROUPS = [
29097
29749
  label: "Check JSON value",
29098
29750
  code: `sp.test("JSON field equals value", function() {
29099
29751
  sp.expect(json.field).to.equal("expected_value");
29100
- });`
29101
- },
29102
- {
29103
- label: "Validate JSON schema (tv4)",
29104
- code: `sp.test("JSON matches schema", function() {
29105
- const schema = {
29106
- type: "object",
29107
- properties: {
29108
- id: { type: "number" },
29109
- name: { type: "string" }
29110
- },
29111
- required: ["id", "name"]
29112
- };
29113
- sp.expect(tv4.validate(json, schema)).to.be.true;
29114
29752
  });`
29115
29753
  }
29116
29754
  ]
@@ -29328,7 +29966,7 @@ function ScriptsTab({ request: request2, onChange }) {
29328
29966
  value: value2,
29329
29967
  height: "100%",
29330
29968
  theme: oneDark,
29331
- extensions,
29969
+ extensions: [...extensions, ...cmLabel(t("Script editor"))],
29332
29970
  onChange: handleChange,
29333
29971
  basicSetup: { lineNumbers: true, foldGutter: false, autocompletion: false }
29334
29972
  }
@@ -29501,7 +30139,7 @@ function SchemaTab({ request: request2, onChange }) {
29501
30139
  height: "300px",
29502
30140
  maxHeight: "50vh",
29503
30141
  theme: oneDark,
29504
- extensions: [json()],
30142
+ extensions: [json(), ...cmLabel(t("JSON schema"))],
29505
30143
  onChange: (val) => setSchema(val),
29506
30144
  placeholder: '{\n "type": "object",\n "properties": {}\n}',
29507
30145
  basicSetup: { lineNumbers: true, foldGutter: true }
@@ -39174,6 +39812,39 @@ function VariablesTab({ request: request2 }) {
39174
39812
  if (name in requestVars) return;
39175
39813
  addRow(name, valueOf(name) === "••••••••" ? "" : `{{${name}}}`);
39176
39814
  };
39815
+ const folderChain = reactExports.useMemo(() => col ? findFolderPath(col.rootFolder, request2.id) : [], [col, request2.id]);
39816
+ const folderLocFor = (name) => {
39817
+ if (!col) return null;
39818
+ for (let i = folderChain.length - 1; i >= 0; i--) {
39819
+ if (folderChain[i].variables && name in folderChain[i].variables) {
39820
+ return { kind: "folder", collectionId: col.id, folderId: folderChain[i].id };
39821
+ }
39822
+ }
39823
+ return null;
39824
+ };
39825
+ const locForScope = (scope, name) => {
39826
+ switch (scope) {
39827
+ case "request":
39828
+ return col ? { kind: "request", collectionId: col.id, requestId: request2.id } : null;
39829
+ case "folder":
39830
+ return folderLocFor(name);
39831
+ case "collection":
39832
+ return col ? { kind: "collection", collectionId: col.id } : null;
39833
+ case "environment":
39834
+ return activeEnv ? { kind: "environment", environmentId: activeEnv.id } : null;
39835
+ case "global":
39836
+ return { kind: "global" };
39837
+ }
39838
+ };
39839
+ const reseedRows = () => {
39840
+ const base = useStore$1.getState().collections[col?.id ?? ""]?.data.requests[request2.id];
39841
+ const enabled = base?.variables ?? {};
39842
+ const disabled = base?.variablesDisabled ?? {};
39843
+ setRows([
39844
+ ...Object.entries(enabled).map(([key, value2]) => ({ key, value: value2, enabled: true })),
39845
+ ...Object.entries(disabled).map(([key, value2]) => ({ key, value: value2, enabled: false }))
39846
+ ]);
39847
+ };
39177
39848
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-5 text-xs", children: [
39178
39849
  /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { children: [
39179
39850
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
@@ -39225,6 +39896,14 @@ function VariablesTab({ request: request2 }) {
39225
39896
  }
39226
39897
  ),
39227
39898
  shadows && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 text-[9px] uppercase tracking-wider text-fuchsia-400 border border-fuchsia-500/30 rounded px-1 py-px", title: t("Overrides a higher-level variable of the same name"), children: t("override") }),
39899
+ !isExample && key && col && /* @__PURE__ */ jsxRuntimeExports.jsx(
39900
+ MoveVariableMenu,
39901
+ {
39902
+ from: { kind: "request", collectionId: col.id, requestId: request2.id },
39903
+ name: key,
39904
+ onMoved: reseedRows
39905
+ }
39906
+ ),
39228
39907
  /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => removeRow(i), className: "shrink-0 text-surface-500 hover:text-red-400 p-1", title: t("Remove"), children: /* @__PURE__ */ jsxRuntimeExports.jsx(TrashIcon, {}) })
39229
39908
  ] }, i);
39230
39909
  }) })
@@ -39272,6 +39951,7 @@ function VariablesTab({ request: request2 }) {
39272
39951
  children: t("override")
39273
39952
  }
39274
39953
  ),
39954
+ locForScope(scope, name) && /* @__PURE__ */ jsxRuntimeExports.jsx(MoveVariableMenu, { from: locForScope(scope, name), name, onMoved: reseedRows }),
39275
39955
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `shrink-0 text-[9px] uppercase tracking-wider border rounded px-1 py-px ${SCOPE_BADGE[scope]}`, children: SCOPE_LABEL[scope] })
39276
39956
  ] }, name);
39277
39957
  }) })
@@ -41674,6 +42354,7 @@ function RequestBuilder({ request: request2 }) {
41674
42354
  ) : /* @__PURE__ */ jsxRuntimeExports.jsxs(
41675
42355
  "select",
41676
42356
  {
42357
+ "aria-label": t("HTTP method"),
41677
42358
  value: METHODS.includes(request2.method) ? request2.method : "__current__",
41678
42359
  onChange: (e) => {
41679
42360
  if (e.target.value === "__custom__") setCustomVerb(true);
@@ -43828,8 +44509,8 @@ function ResponseViewer() {
43828
44509
  " KB"
43829
44510
  ] })
43830
44511
  ] }),
43831
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { role: "tablist", tabIndex: -1, "aria-label": t("Response sections"), onKeyDown: onTablistKey, className: "flex items-center gap-0 min-w-0 ml-1", children: [
43832
- tabList.map((def) => renderTabButton(def, "inline")),
44512
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-0 min-w-0 ml-1", children: [
44513
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { role: "tablist", tabIndex: -1, "aria-label": t("Response sections"), onKeyDown: onTablistKey, className: "flex items-center gap-0 min-w-0", children: tabList.map((def) => renderTabButton(def, "inline")) }),
43833
44514
  /* @__PURE__ */ jsxRuntimeExports.jsx(
43834
44515
  OverflowMenu,
43835
44516
  {
@@ -44034,7 +44715,7 @@ function ResponseViewer() {
44034
44715
  {
44035
44716
  value: jqResult ?? "",
44036
44717
  theme: oneDark,
44037
- extensions: [json()],
44718
+ extensions: [json(), ...cmLabel(t("Filtered response"))],
44038
44719
  readOnly: true,
44039
44720
  basicSetup: { lineNumbers: true, foldGutter: true }
44040
44721
  }
@@ -44058,7 +44739,7 @@ function ResponseViewer() {
44058
44739
  {
44059
44740
  value: displayBody,
44060
44741
  theme: oneDark,
44061
- extensions: isJson ? [json()] : isXml ? [xml()] : [],
44742
+ extensions: [...isJson ? [json()] : isXml ? [xml()] : [], ...cmLabel(t("Response body"))],
44062
44743
  readOnly: true,
44063
44744
  basicSetup: { lineNumbers: true, foldGutter: true }
44064
44745
  }
@@ -45521,7 +46202,6 @@ function HistoryRow({
45521
46202
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(
45522
46203
  "div",
45523
46204
  {
45524
- role: "button",
45525
46205
  tabIndex: 0,
45526
46206
  onClick: onSelect,
45527
46207
  onKeyDown: (e) => {
@@ -45652,7 +46332,7 @@ function WelcomeScreen() {
45652
46332
  /* @__PURE__ */ jsxRuntimeExports.jsxs("h1", { className: "text-2xl font-semibold mb-1", children: [
45653
46333
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--wordmark-muted)" }, children: "API" }),
45654
46334
  " ",
45655
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#6aa3c8" }, children: "Spector" })
46335
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--wordmark-accent)" }, children: "Spector" })
45656
46336
  ] }),
45657
46337
  /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] mb-3", style: { color: "var(--text-muted)" }, children: [
45658
46338
  t("by"),
@@ -45662,13 +46342,13 @@ function WelcomeScreen() {
45662
46342
  {
45663
46343
  onClick: () => window.electron.openExternal("https://testsmith.io"),
45664
46344
  className: "hover:underline focus:outline-none",
45665
- style: { color: "#6aa3c8" },
46345
+ style: { color: "var(--wordmark-accent)" },
45666
46346
  children: "Testsmith"
45667
46347
  }
45668
46348
  )
45669
46349
  ] }),
45670
46350
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-surface-400 text-sm max-w-sm", children: t("Local-first API testing with Robot Framework & Playwright code generation. Secrets stay on your machine.") }),
45671
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] mt-3", style: { color: "var(--text-muted)" }, children: t("version :version", { version: "0.8.9" }) })
46351
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] mt-3", style: { color: "var(--text-muted)" }, children: t("version :version", { version: "0.9.0" }) })
45672
46352
  ] }),
45673
46353
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3 w-64", children: [
45674
46354
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -45699,7 +46379,7 @@ function WelcomeScreen() {
45699
46379
  onKeyDown: (e) => {
45700
46380
  if (e.key === "Enter") openFromGit();
45701
46381
  },
45702
- placeholder: "https://github.com/owner/repo",
46382
+ placeholder: "https://github.com/owner/repo or git@host:owner/repo.git",
45703
46383
  autoFocus: true,
45704
46384
  disabled: busy || gitBusy,
45705
46385
  className: "px-3 py-2 bg-surface-900 border border-surface-700 rounded text-xs focus:outline-none focus:border-blue-600 disabled:opacity-60"
@@ -46171,7 +46851,7 @@ function EnvironmentEditor({ onClose }) {
46171
46851
  placeholder: t("Environment name")
46172
46852
  }
46173
46853
  ),
46174
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "text-surface-400 hover:text-white text-lg leading-none", children: "×" })
46854
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, "aria-label": "Close", title: "Close", className: "text-surface-400 hover:text-white text-lg leading-none", children: "×" })
46175
46855
  ] }),
46176
46856
  nameError && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-red-400 mt-1", children: nameError }),
46177
46857
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 mt-2", children: [
@@ -46295,14 +46975,24 @@ function EnvironmentEditor({ onClose }) {
46295
46975
  )
46296
46976
  ] })
46297
46977
  ] }),
46298
- /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-2 py-1.5", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
46299
- "button",
46300
- {
46301
- onClick: () => removeVar(idx),
46302
- className: "text-surface-400 hover:text-red-400 opacity-0 group-hover:opacity-100 transition-all",
46303
- children: "×"
46304
- }
46305
- ) })
46978
+ /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-2 py-1.5", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 justify-end", children: [
46979
+ v.key.trim() && env2 && /* @__PURE__ */ jsxRuntimeExports.jsx(
46980
+ MoveVariableMenu,
46981
+ {
46982
+ from: { kind: "environment", environmentId: env2.id },
46983
+ name: v.key.trim(),
46984
+ buttonClassName: "text-[9px] uppercase tracking-wider text-surface-500 hover:text-blue-400 border border-surface-700 hover:border-blue-500/40 rounded px-1 py-px opacity-0 group-hover:opacity-100 transition-all"
46985
+ }
46986
+ ),
46987
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
46988
+ "button",
46989
+ {
46990
+ onClick: () => removeVar(idx),
46991
+ className: "text-surface-400 hover:text-red-400 opacity-0 group-hover:opacity-100 transition-all",
46992
+ children: "×"
46993
+ }
46994
+ )
46995
+ ] }) })
46306
46996
  ] }),
46307
46997
  /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { children: [
46308
46998
  /* @__PURE__ */ jsxRuntimeExports.jsx("td", {}),
@@ -46472,6 +47162,7 @@ function EnvironmentBar({ inline = false }) {
46472
47162
  {
46473
47163
  value: activeEnvironmentId ?? "",
46474
47164
  onChange: (e) => handleEnvChange(e.target.value || null),
47165
+ "aria-label": t("Active environment"),
46475
47166
  className: "bg-surface-800 border border-surface-700 rounded px-2 py-0.5 text-xs focus:outline-none focus:border-blue-500 max-w-[140px]",
46476
47167
  style: { color: "var(--text-primary)" },
46477
47168
  children: [
@@ -46893,6 +47584,7 @@ function WorkspaceSettingsModal({ onClose, initialTab }) {
46893
47584
  {
46894
47585
  value: defaultEnvironment,
46895
47586
  onChange: (e) => setDefaultEnvironment(e.target.value),
47587
+ "aria-label": t("Default environment"),
46896
47588
  className: "bg-surface-800 border border-surface-700 rounded px-2.5 py-1.5 focus:outline-none focus:border-blue-500",
46897
47589
  children: [
46898
47590
  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: t("(none)") }),
@@ -46909,6 +47601,7 @@ function WorkspaceSettingsModal({ onClose, initialTab }) {
46909
47601
  {
46910
47602
  value: defaultRequestTab,
46911
47603
  onChange: (e) => setDefaultRequestTab(e.target.value),
47604
+ "aria-label": t("Default request tab"),
46912
47605
  className: "bg-surface-800 border border-surface-700 rounded px-2.5 py-1.5 focus:outline-none focus:border-blue-500",
46913
47606
  children: [
46914
47607
  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "docs", children: t("Docs") }),
@@ -46980,6 +47673,7 @@ function WorkspaceSettingsModal({ onClose, initialTab }) {
46980
47673
  {
46981
47674
  value: locale,
46982
47675
  onChange: (e) => setLocale(e.target.value),
47676
+ "aria-label": t("Language"),
46983
47677
  className: "bg-surface-800 hover:bg-surface-700 text-surface-300 text-xs rounded py-1.5 px-2 outline-none",
46984
47678
  children: Object.entries(LOCALES).map(([code, name]) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: code, children: name }, code))
46985
47679
  }
@@ -47305,6 +47999,7 @@ function WorkspaceSettingsModal({ onClose, initialTab }) {
47305
47999
  {
47306
48000
  value: vAuthMethod,
47307
48001
  onChange: (e) => setVAuthMethod(e.target.value),
48002
+ "aria-label": t("Auth method"),
47308
48003
  className: "bg-surface-800 border border-surface-700 rounded px-2.5 py-1.5 focus:outline-none focus:border-blue-500",
47309
48004
  children: [
47310
48005
  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "token", children: t("Token / OIDC") }),
@@ -47364,6 +48059,7 @@ function WorkspaceSettingsModal({ onClose, initialTab }) {
47364
48059
  {
47365
48060
  value: vKvVersion,
47366
48061
  onChange: (e) => setVKvVersion(e.target.value),
48062
+ "aria-label": t("KV version"),
47367
48063
  className: "bg-surface-800 border border-surface-700 rounded px-2.5 py-1.5 focus:outline-none focus:border-blue-500",
47368
48064
  children: [
47369
48065
  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "auto", children: "auto" }),
@@ -47417,6 +48113,7 @@ function WorkspaceSettingsModal({ onClose, initialTab }) {
47417
48113
  value: azVault,
47418
48114
  onChange: (e) => setAzVault(e.target.value),
47419
48115
  placeholder: "acme-kv",
48116
+ "aria-label": t("Azure vault"),
47420
48117
  className: `${inputCls$1} placeholder-surface-600`
47421
48118
  }
47422
48119
  )
@@ -47428,6 +48125,7 @@ function WorkspaceSettingsModal({ onClose, initialTab }) {
47428
48125
  {
47429
48126
  value: azTenantId,
47430
48127
  onChange: (e) => setAzTenantId(e.target.value),
48128
+ "aria-label": t("Tenant id"),
47431
48129
  className: inputCls$1
47432
48130
  }
47433
48131
  )
@@ -47439,6 +48137,7 @@ function WorkspaceSettingsModal({ onClose, initialTab }) {
47439
48137
  {
47440
48138
  value: azClientId,
47441
48139
  onChange: (e) => setAzClientId(e.target.value),
48140
+ "aria-label": t("Client id"),
47442
48141
  className: inputCls$1
47443
48142
  }
47444
48143
  )
@@ -48687,7 +49386,7 @@ function Toolbar({ onOpenDocs: _onOpenDocs }) {
48687
49386
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-semibold tracking-wide", children: [
48688
49387
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--wordmark-muted)" }, children: "API" }),
48689
49388
  " ",
48690
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#6aa3c8" }, children: "Spector" })
49389
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--wordmark-accent)" }, children: "Spector" })
48691
49390
  ] }),
48692
49391
  /* @__PURE__ */ jsxRuntimeExports.jsx(
48693
49392
  "button",
@@ -48939,18 +49638,18 @@ function buildHtmlReport(results, summary2, meta = {}) {
48939
49638
  :root {
48940
49639
  --bg: #0f1117; --bg-surface: #161b22; --bg-panel: #0d1117;
48941
49640
  --border: #21262d; --border-hover:#30363d;
48942
- --text: #c9d1d9; --text-bright: #e6edf3; --text-muted: #8b949e; --text-dim: #484f58;
49641
+ --text: #c9d1d9; --text-bright: #e6edf3; --text-muted: #8b949e; --text-dim: #818992;
48943
49642
  --green: #3fb950; --red: #f85149; --amber: #d29922; --blue: #79c0ff;
48944
49643
  --badge-pass-bg: #0d3a1e; --badge-fail-bg: #3d1014; --badge-err-bg: #3d2a00; --badge-skip-bg: #21262d;
48945
49644
  --hook-before-border: #7c3aed; --hook-after-border: #0e7490;
48946
49645
  --hook-before-bg: #4c1d95; --hook-before-fg: #c4b5fd;
48947
49646
  --hook-after-bg: #164e63; --hook-after-fg: #67e8f9;
48948
- --link: #3d7fb2;
49647
+ --link: #58a6ff;
48949
49648
  }
48950
49649
  html.light {
48951
49650
  --bg: #ffffff; --bg-surface: #f6f8fa; --bg-panel: #ffffff;
48952
49651
  --border: #d0d7de; --border-hover:#c4c9cf;
48953
- --text: #1f2328; --text-bright: #1f2328; --text-muted: #656d76; --text-dim: #8b949e;
49652
+ --text: #1f2328; --text-bright: #1f2328; --text-muted: #656d76; --text-dim: #6b7280;
48954
49653
  --green: #1a7f37; --red: #cf222e; --amber: #9a6700; --blue: #0969da;
48955
49654
  --badge-pass-bg: #dafbe1; --badge-fail-bg: #ffebe9; --badge-err-bg: #fff8c5; --badge-skip-bg: #f6f8fa;
48956
49655
  --hook-before-border: #8b5cf6; --hook-after-border: #06b6d4;
@@ -50737,6 +51436,13 @@ function CollectionPanel() {
50737
51436
  const disabled = Object.fromEntries(rows.filter((r) => !r.enabled && r.key.trim()).map((r) => [r.key.trim(), r.value]));
50738
51437
  updateCollectionVariables(activeCollectionId, variables, disabled);
50739
51438
  }
51439
+ function reseedVarRows() {
51440
+ const data = useStore$1.getState().collections[activeCollectionId ?? ""]?.data;
51441
+ setVarRows([
51442
+ ...Object.entries(data?.collectionVariables ?? {}).map(([key, value2]) => ({ key, value: value2, enabled: true })),
51443
+ ...Object.entries(data?.collectionVariablesDisabled ?? {}).map(([key, value2]) => ({ key, value: value2, enabled: false }))
51444
+ ]);
51445
+ }
50740
51446
  if (!activeCollectionId) {
50741
51447
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-full text-surface-400 text-sm", children: t("Select a request from the sidebar") });
50742
51448
  }
@@ -50817,7 +51523,17 @@ function CollectionPanel() {
50817
51523
  activeTab === "data" && /* @__PURE__ */ jsxRuntimeExports.jsx(DataSetEditor, { ds, onChange: setDs, exportName: col.name, scopeLabel: "collection" }),
50818
51524
  activeTab === "variables" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2 text-xs", children: [
50819
51525
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-surface-500", children: t("Variables scoped to this collection. They override environment and global variables, and are overridden by folder and request variables (and runtime / CLI / data-row values). Reference them anywhere with :token.", { token: "{{name}}" }) }),
50820
- /* @__PURE__ */ jsxRuntimeExports.jsx(KVTable, { rows: varRows, onChange: setVars, keyPlaceholder: t("name"), valuePlaceholder: t("value") }),
51526
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
51527
+ KVTable,
51528
+ {
51529
+ rows: varRows,
51530
+ onChange: setVars,
51531
+ keyPlaceholder: t("name"),
51532
+ valuePlaceholder: t("value"),
51533
+ moveFrom: () => activeCollectionId ? { kind: "collection", collectionId: activeCollectionId } : null,
51534
+ onMoved: reseedVarRows
51535
+ }
51536
+ ),
50821
51537
  /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-surface-600 text-[11px]", children: [
50822
51538
  t("Scripts can also set these at runtime via"),
50823
51539
  " ",
@@ -50859,6 +51575,13 @@ function FolderPanel() {
50859
51575
  const variablesDisabled = Object.fromEntries(rows.filter((r) => !r.enabled && r.key.trim()).map((r) => [r.key.trim(), r.value]));
50860
51576
  updateFolder(cid, folder2.id, { variables, variablesDisabled });
50861
51577
  }
51578
+ function reseedVarRows() {
51579
+ const f = useStore$1.getState().collections[cid]?.data && findFolder$1(useStore$1.getState().collections[cid].data.rootFolder, folder2.id);
51580
+ setVarRows([
51581
+ ...Object.entries(f?.variables ?? {}).map(([key, value2]) => ({ key, value: value2, enabled: true })),
51582
+ ...Object.entries(f?.variablesDisabled ?? {}).map(([key, value2]) => ({ key, value: value2, enabled: false }))
51583
+ ]);
51584
+ }
50862
51585
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col h-full", children: [
50863
51586
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-6 py-4 border-b border-surface-800 flex-shrink-0 flex items-center justify-between", children: [
50864
51587
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
@@ -50909,7 +51632,17 @@ function FolderPanel() {
50909
51632
  activeTab === "data" && /* @__PURE__ */ jsxRuntimeExports.jsx(DataSetEditor, { ds, onChange: (next) => updateFolder(cid, folder2.id, { dataSet: next }), exportName: folder2.name, scopeLabel: "folder" }),
50910
51633
  activeTab === "variables" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2", children: [
50911
51634
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-surface-500 leading-relaxed", children: t("Variables scoped to this folder. They override collection and environment variables, and are overridden by an inner folder, a request’s own variables, and runtime / CLI / data-row values. Reference them anywhere with :token.", { token: "{{name}}" }) }),
50912
- /* @__PURE__ */ jsxRuntimeExports.jsx(KVTable, { rows: varRows, onChange: setVars, keyPlaceholder: t("name"), valuePlaceholder: t("value") })
51635
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
51636
+ KVTable,
51637
+ {
51638
+ rows: varRows,
51639
+ onChange: setVars,
51640
+ keyPlaceholder: t("name"),
51641
+ valuePlaceholder: t("value"),
51642
+ moveFrom: () => ({ kind: "folder", collectionId: cid, folderId: folder2.id }),
51643
+ onMoved: reseedVarRows
51644
+ }
51645
+ )
50913
51646
  ] })
50914
51647
  ] })
50915
51648
  ] });
@@ -53606,7 +54339,7 @@ function ConflictEditor({ path, onClose, onResolved }) {
53606
54339
  children: t("Edit manually")
53607
54340
  }
53608
54341
  ),
53609
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "text-surface-400 hover:text-white text-lg leading-none pl-1", children: "×" })
54342
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, "aria-label": "Close", title: "Close", className: "text-surface-400 hover:text-white text-lg leading-none pl-1", children: "×" })
53610
54343
  ] })
53611
54344
  ] }),
53612
54345
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto min-h-0", children: [
@@ -53919,7 +54652,6 @@ function ChangesTab({ status, onRefresh }) {
53919
54652
  "div",
53920
54653
  {
53921
54654
  className: `flex items-center gap-2 px-3 py-1 hover:bg-surface-800/50 cursor-pointer group text-xs ${diffFile === f.path && diffStaged ? "bg-surface-800" : ""}`,
53922
- role: "button",
53923
54655
  tabIndex: 0,
53924
54656
  onClick: () => showDiff(f, true),
53925
54657
  onKeyDown: onActivateKey(() => showDiff(f, true)),
@@ -53959,7 +54691,6 @@ function ChangesTab({ status, onRefresh }) {
53959
54691
  "div",
53960
54692
  {
53961
54693
  className: `flex items-center gap-2 px-3 py-1 hover:bg-surface-800/50 cursor-pointer group text-xs ${diffFile === f.path && !diffStaged ? "bg-surface-800" : ""}`,
53962
- role: "button",
53963
54694
  tabIndex: 0,
53964
54695
  onClick: () => showDiff(f, false),
53965
54696
  onKeyDown: onActivateKey(() => showDiff(f, false)),
@@ -53989,7 +54720,6 @@ function ChangesTab({ status, onRefresh }) {
53989
54720
  "div",
53990
54721
  {
53991
54722
  className: `flex items-center gap-2 px-3 py-1 hover:bg-surface-800/50 cursor-pointer group text-xs ${diffFile === path && !diffStaged ? "bg-surface-800" : ""}`,
53992
- role: "button",
53993
54723
  tabIndex: 0,
53994
54724
  onClick: () => showDiff({ path, status: "modified" }, false),
53995
54725
  onKeyDown: onActivateKey(() => showDiff({ path, status: "modified" }, false)),
@@ -55174,6 +55904,9 @@ function pretty(v) {
55174
55904
  return esc(String(v));
55175
55905
  }
55176
55906
  }
55907
+ function headerLines(h) {
55908
+ return Object.entries(h).map(([k, v]) => `${k}: ${v}`).join("\n");
55909
+ }
55177
55910
  const STATUS_CLS = {
55178
55911
  passed: "badge-pass",
55179
55912
  failed: "badge-fail",
@@ -55191,8 +55924,18 @@ function blockDetail(b) {
55191
55924
  ).join("");
55192
55925
  parts.push(`<div class="section-label">Tests</div><div class="tests-wrap">${rows}</div>`);
55193
55926
  }
55194
- if (b.type === "request" && b.resolvedUrl) {
55195
- parts.push(`<div class="section-label">Request</div><div class="mono url">${esc(b.method ?? "")} ${esc(b.resolvedUrl)}</div>`);
55927
+ if (b.type === "request" && (b.resolvedUrl || b.http)) {
55928
+ const h = b.http;
55929
+ parts.push('<div class="section-label">Request</div>');
55930
+ if (b.resolvedUrl) parts.push(`<div class="mono url">${esc(b.method ?? "")} ${esc(b.resolvedUrl)}</div>`);
55931
+ if (h?.reqHeaders && Object.keys(h.reqHeaders).length) parts.push(`<pre class="code-block">${esc(headerLines(h.reqHeaders))}</pre>`);
55932
+ if (h?.reqBody) parts.push(`<pre class="code-block">${pretty(h.reqBody)}</pre>`);
55933
+ parts.push('<div class="section-label">Response</div>');
55934
+ const statusLine = b.httpStatus != null ? `${b.httpStatus}${h?.statusText ? " " + h.statusText : ""}${h?.bodySize != null ? ` · ${h.bodySize} bytes` : ""}` : "(no response received)";
55935
+ parts.push(`<div class="mono url">${esc(statusLine)}</div>`);
55936
+ if (h?.resHeaders && Object.keys(h.resHeaders).length) parts.push(`<pre class="code-block">${esc(headerLines(h.resHeaders))}</pre>`);
55937
+ if (h?.resBody) parts.push(`<pre class="code-block">${pretty(h.resBody)}</pre>`);
55938
+ if (h?.truncated) parts.push('<div class="muted" style="font-size:11px">Request/response body truncated for the report.</div>');
55196
55939
  }
55197
55940
  if (b.type === "log" && b.message) {
55198
55941
  parts.push(`<div class="section-label">Message</div><pre class="code-block">${esc(b.message)}</pre>`);
@@ -55402,7 +56145,10 @@ function useFlowRunner() {
55402
56145
  iteration: b.iteration,
55403
56146
  atMs: b.atMs,
55404
56147
  message: b.message,
55405
- value: b.display
56148
+ value: b.display,
56149
+ method: b.method,
56150
+ resolvedUrl: b.resolvedUrl,
56151
+ http: b.http
55406
56152
  }));
55407
56153
  const rebuiltOutputs = summary2.blocks.filter((b) => b.type === "log" || b.type === "display").map((b) => b.type === "log" ? { kind: "log", blockId: b.blockId, message: b.message } : { kind: "display", blockId: b.blockId, value: b.display, label: b.label });
55408
56154
  setState((prev) => ({
@@ -55857,6 +56603,7 @@ function AddBlockMenu({ onAdd: onAdd2 }) {
55857
56603
  ] })
55858
56604
  ] });
55859
56605
  }
56606
+ const headerText = (h) => Object.entries(h).map(([k, v]) => `${k}: ${v}`).join("\n");
55860
56607
  const LOG_ICON = {
55861
56608
  passed: "✓",
55862
56609
  failed: "✗",
@@ -55893,6 +56640,15 @@ function formatLogText(log) {
55893
56640
  function BottomPanel({ runner, flowName, problems, onFocusBlock, tab, setTab }) {
55894
56641
  const t = useT();
55895
56642
  const { outputs, variables, data, log, summary: summary2 } = runner;
56643
+ const [openLog, setOpenLog] = reactExports.useState(/* @__PURE__ */ new Set());
56644
+ reactExports.useEffect(() => {
56645
+ if (!summary2) return;
56646
+ const fails = /* @__PURE__ */ new Set();
56647
+ log.forEach((e, i) => {
56648
+ if ((e.http || e.resolvedUrl) && (e.status === "failed" || e.status === "error")) fails.add(i);
56649
+ });
56650
+ setOpenLog(fails);
56651
+ }, [summary2]);
55896
56652
  const varEntries = Object.entries(variables);
55897
56653
  const dataEntries = Object.entries(data).filter(([k, v]) => typeof v === "object" && v !== null || !(k in variables));
55898
56654
  const hasVars = varEntries.length > 0 || dataEntries.length > 0;
@@ -55967,24 +56723,63 @@ function BottomPanel({ runner, flowName, problems, onFocusBlock, tab, setTab })
55967
56723
  ": ",
55968
56724
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-300 break-all", children: typeof e.value === "string" ? e.value : JSON.stringify(e.value) })
55969
56725
  ] }, i);
55970
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-baseline gap-2", children: [
55971
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-600 w-14 shrink-0 text-right", children: at }),
55972
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: LOG_ICON_CLS[e.status ?? "done"], children: LOG_ICON[e.status ?? "done"] ?? "•" }),
55973
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-300", children: [
55974
- e.label ?? e.type,
55975
- e.iteration != null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-600", children: [
55976
- " #",
55977
- e.iteration
55978
- ] })
55979
- ] }),
55980
- e.httpStatus != null && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: e.httpStatus < 400 ? "text-emerald-400" : "text-red-400", children: e.httpStatus }),
55981
- e.durationMs != null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-600", children: [
55982
- e.durationMs,
55983
- "ms"
55984
- ] }),
55985
- e.error && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-red-400 break-all", children: [
55986
- "— ",
55987
- e.error
56726
+ const hasDetail2 = !!(e.http || e.resolvedUrl);
56727
+ const open2 = openLog.has(i);
56728
+ const toggle = () => setOpenLog((s) => {
56729
+ const n2 = new Set(s);
56730
+ if (n2.has(i)) n2.delete(i);
56731
+ else n2.add(i);
56732
+ return n2;
56733
+ });
56734
+ const reqHeaders = e.http?.reqHeaders;
56735
+ const resHeaders = e.http?.resHeaders;
56736
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col", children: [
56737
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
56738
+ "div",
56739
+ {
56740
+ className: `flex items-baseline gap-2 ${hasDetail2 ? "cursor-pointer hover:bg-surface-800/40 rounded" : ""}`,
56741
+ onClick: hasDetail2 ? toggle : void 0,
56742
+ children: [
56743
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-600 w-14 shrink-0 text-right", children: at }),
56744
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: LOG_ICON_CLS[e.status ?? "done"], children: LOG_ICON[e.status ?? "done"] ?? "•" }),
56745
+ hasDetail2 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-600 w-2 shrink-0", children: open2 ? "▾" : "▸" }),
56746
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-300", children: [
56747
+ e.label ?? e.type,
56748
+ e.iteration != null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-600", children: [
56749
+ " #",
56750
+ e.iteration
56751
+ ] })
56752
+ ] }),
56753
+ e.httpStatus != null && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: e.httpStatus < 400 ? "text-emerald-400" : "text-red-400", children: e.httpStatus }),
56754
+ e.durationMs != null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-600", children: [
56755
+ e.durationMs,
56756
+ "ms"
56757
+ ] }),
56758
+ e.error && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-red-400 break-all", children: [
56759
+ "— ",
56760
+ e.error
56761
+ ] })
56762
+ ]
56763
+ }
56764
+ ),
56765
+ open2 && hasDetail2 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ml-16 mt-1 mb-2 flex flex-col gap-1 text-[10px]", children: [
56766
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-surface-500 uppercase tracking-wider", children: t("Request") }),
56767
+ e.resolvedUrl && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-surface-300 break-all", children: [
56768
+ e.method,
56769
+ " ",
56770
+ e.resolvedUrl
56771
+ ] }),
56772
+ reqHeaders && Object.keys(reqHeaders).length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "whitespace-pre-wrap break-all text-surface-400 bg-surface-900 rounded p-1.5 m-0", children: headerText(reqHeaders) }),
56773
+ e.http?.reqBody && /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "whitespace-pre-wrap break-all text-surface-300 bg-surface-900 rounded p-1.5 m-0", children: e.http.reqBody }),
56774
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-surface-500 uppercase tracking-wider mt-1", children: t("Response") }),
56775
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: e.httpStatus != null && e.httpStatus < 400 ? "text-emerald-400" : "text-red-400", children: [
56776
+ e.httpStatus != null ? e.httpStatus : t("(no response)"),
56777
+ e.http?.statusText ? " " + e.http.statusText : "",
56778
+ e.http?.bodySize != null ? ` · ${e.http.bodySize} bytes` : ""
56779
+ ] }),
56780
+ resHeaders && Object.keys(resHeaders).length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "whitespace-pre-wrap break-all text-surface-400 bg-surface-900 rounded p-1.5 m-0", children: headerText(resHeaders) }),
56781
+ e.http?.resBody && /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "whitespace-pre-wrap break-all text-surface-300 bg-surface-900 rounded p-1.5 m-0", children: e.http.resBody }),
56782
+ e.http?.truncated && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-surface-600", children: t("body truncated") })
55988
56783
  ] })
55989
56784
  ] }, i);
55990
56785
  }) }) : active2 === "output" ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col gap-1.5", children: outputs.map((o, i) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-mono", children: o.kind === "log" ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-cyan-300", children: [
@@ -56872,17 +57667,17 @@ function ActivityBarBtn({
56872
57667
  dataTour
56873
57668
  }) {
56874
57669
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative group/ab", "data-tour": dataTour, children: [
56875
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
57670
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
56876
57671
  "button",
56877
57672
  {
56878
57673
  onClick,
57674
+ "aria-label": title,
57675
+ "aria-pressed": active2,
56879
57676
  className: `relative w-10 h-10 flex items-center justify-center rounded transition-colors ${active2 ? "text-white bg-surface-800" : "text-surface-600 hover:text-surface-300 hover:bg-surface-800/50"}`,
56880
- children: [
56881
- children2,
56882
- badge !== void 0 && badge > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "absolute top-1 right-1 text-[9px] bg-surface-600 text-white rounded-full w-3.5 h-3.5 flex items-center justify-center font-medium leading-none", children: badge > 9 ? "9+" : badge })
56883
- ]
57677
+ children: children2
56884
57678
  }
56885
57679
  ),
57680
+ badge !== void 0 && badge > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { "aria-hidden": "true", className: "pointer-events-none absolute top-1 right-1 text-[9px] bg-surface-600 text-white rounded-full w-3.5 h-3.5 flex items-center justify-center font-medium leading-none", children: badge > 9 ? "9+" : badge }),
56886
57681
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pointer-events-none absolute left-full top-1/2 -translate-y-1/2 ml-2 z-50 hidden group-hover/ab:block", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "whitespace-nowrap rounded px-2 py-1 text-[11px] bg-surface-900 text-[var(--text-primary)] border border-surface-700 shadow-lg", children: title }) })
56887
57682
  ] });
56888
57683
  }
@@ -56907,35 +57702,45 @@ const TabRow = React.memo(function TabRow2({
56907
57702
  onContextMenu
56908
57703
  }) {
56909
57704
  const t = useT();
56910
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(
56911
- "div",
56912
- {
56913
- role: "button",
56914
- tabIndex: 0,
56915
- onClick: () => onActivate(tabId),
56916
- onKeyDown: onActivateKey(() => onActivate(tabId)),
56917
- onContextMenu: (e) => {
56918
- e.preventDefault();
56919
- onContextMenu(tabId, e.clientX, e.clientY);
56920
- },
56921
- className: `group flex items-center gap-1.5 px-3 py-1.5 border-r border-surface-800 cursor-pointer min-w-0 max-w-[200px] flex-shrink-0 transition-colors ${isActive ? "bg-surface-900 border-b-2 border-b-blue-500 -mb-px" : "hover:bg-surface-900/50 text-surface-600"}`,
56922
- children: [
56923
- kind === "folder" ? /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-3 h-3 shrink-0 text-amber-600", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M2 5a2 2 0 012-2h3.5l2 2H16a2 2 0 012 2v6a2 2 0 01-2 2H4a2 2 0 01-2-2V5z" }) }) : kind === "collection" ? /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-3 h-3 shrink-0 text-blue-400", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M3 4h14v2.5H3V4zm0 4.75h14v2.5H3v-2.5zM3 13.5h14V16H3v-2.5z" }) }) : method ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-[10px] font-bold shrink-0 ${TAB_METHOD_COLORS[method] ?? "text-gray-400"}`, children: method }) : null,
56924
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-xs truncate ${isActive ? "text-white" : ""}`, children: name }),
56925
- /* @__PURE__ */ jsxRuntimeExports.jsx(
56926
- "button",
56927
- {
56928
- onClick: (e) => {
56929
- e.stopPropagation();
56930
- onClose(tabId);
56931
- },
56932
- className: "ml-auto opacity-0 group-hover:opacity-100 shrink-0 text-surface-600 hover:text-white transition-all leading-none",
56933
- title: t("Close tab"),
56934
- children: "×"
56935
- }
56936
- )
56937
- ]
56938
- }
57705
+ return (
57706
+ // Plain container (no interactive role) so the activate + close buttons below
57707
+ // are siblings, not nested interactives — screen readers announce both.
57708
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
57709
+ "div",
57710
+ {
57711
+ onContextMenu: (e) => {
57712
+ e.preventDefault();
57713
+ onContextMenu(tabId, e.clientX, e.clientY);
57714
+ },
57715
+ className: `group flex items-center gap-1.5 pr-1 border-r border-surface-800 min-w-0 max-w-[200px] flex-shrink-0 transition-colors ${isActive ? "bg-surface-900 border-b-2 border-b-blue-500 -mb-px" : "hover:bg-surface-900/50 text-surface-600"}`,
57716
+ children: [
57717
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
57718
+ "button",
57719
+ {
57720
+ onClick: () => onActivate(tabId),
57721
+ className: "flex items-center gap-1.5 pl-3 py-1.5 min-w-0 flex-1 cursor-pointer focus:outline-none",
57722
+ children: [
57723
+ kind === "folder" ? /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-3 h-3 shrink-0 text-amber-600", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M2 5a2 2 0 012-2h3.5l2 2H16a2 2 0 012 2v6a2 2 0 01-2 2H4a2 2 0 01-2-2V5z" }) }) : kind === "collection" ? /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-3 h-3 shrink-0 text-blue-400", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M3 4h14v2.5H3V4zm0 4.75h14v2.5H3v-2.5zM3 13.5h14V16H3v-2.5z" }) }) : method ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-[10px] font-bold shrink-0 ${TAB_METHOD_COLORS[method] ?? "text-gray-400"}`, children: method }) : null,
57724
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-xs truncate ${isActive ? "text-white" : ""}`, children: name })
57725
+ ]
57726
+ }
57727
+ ),
57728
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
57729
+ "button",
57730
+ {
57731
+ onClick: (e) => {
57732
+ e.stopPropagation();
57733
+ onClose(tabId);
57734
+ },
57735
+ className: "mr-2 opacity-0 group-hover:opacity-100 focus:opacity-100 shrink-0 text-surface-600 hover:text-white transition-all leading-none",
57736
+ "aria-label": t("Close tab"),
57737
+ title: t("Close tab"),
57738
+ children: "×"
57739
+ }
57740
+ )
57741
+ ]
57742
+ }
57743
+ )
56939
57744
  );
56940
57745
  });
56941
57746
  function App() {
@@ -57197,18 +58002,18 @@ function App() {
57197
58002
  window.electron.platform !== "win32" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "drag-region flex-shrink-0 bg-surface-950 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "no-drag text-[11px] font-medium tracking-widest select-none", style: { color: "var(--text-muted)" }, children: [
57198
58003
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--wordmark-muted)" }, children: "API" }),
57199
58004
  " ",
57200
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#6aa3c8" }, children: "Spector" }),
57201
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ml-2 text-[10px] font-normal opacity-50", children: [
58005
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--wordmark-accent)" }, children: "Spector" }),
58006
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ml-2 text-[10px] font-normal", style: { color: "var(--text-muted)" }, children: [
57202
58007
  "v",
57203
- "0.8.9"
58008
+ "0.9.0"
57204
58009
  ] }),
57205
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "mx-2 opacity-30", children: "·" }),
58010
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "mx-2 opacity-30", "aria-hidden": "true", children: "·" }),
57206
58011
  /* @__PURE__ */ jsxRuntimeExports.jsx(
57207
58012
  "button",
57208
58013
  {
57209
58014
  onClick: () => window.electron.openExternal("https://testsmith.io"),
57210
- className: "no-drag text-[10px] font-normal opacity-60 hover:opacity-100 hover:underline focus:outline-none transition-opacity",
57211
- style: { color: "#6aa3c8" },
58015
+ className: "no-drag text-[10px] font-normal hover:underline focus:outline-none",
58016
+ style: { color: "var(--wordmark-accent)" },
57212
58017
  children: "testsmith.io"
57213
58018
  }
57214
58019
  )
@@ -57512,42 +58317,44 @@ function App() {
57512
58317
  children: /* @__PURE__ */ jsxRuntimeExports.jsx(RequestBuilder, { request: activeRequest })
57513
58318
  }
57514
58319
  ),
57515
- /* @__PURE__ */ jsxRuntimeExports.jsx(
57516
- "div",
57517
- {
57518
- role: "separator",
57519
- "aria-orientation": "vertical",
57520
- "aria-label": "Resize request pane",
57521
- "aria-valuemin": 200,
57522
- "aria-valuenow": requestPaneWidth ?? leftPaneRef.current?.offsetWidth ?? 400,
57523
- tabIndex: 0,
57524
- className: "flex-shrink-0 w-1 relative cursor-col-resize border-x border-surface-800 hover:border-blue-500 focus:border-blue-500 focus:outline-none transition-colors group",
57525
- onMouseDown: (e) => {
57526
- dragging.current = "request";
57527
- dragStart.current = { x: e.clientX, w: leftPaneRef.current?.offsetWidth ?? requestPaneWidth ?? 400 };
57528
- document.body.style.cursor = "col-resize";
57529
- document.body.style.userSelect = "none";
57530
- e.preventDefault();
57531
- },
57532
- onKeyDown: (e) => {
57533
- if (e.key === "ArrowLeft" || e.key === "ArrowRight") {
58320
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-shrink-0 w-1 relative group", children: [
58321
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
58322
+ "div",
58323
+ {
58324
+ role: "separator",
58325
+ "aria-orientation": "vertical",
58326
+ "aria-label": "Resize request pane",
58327
+ "aria-valuemin": 200,
58328
+ "aria-valuenow": requestPaneWidth ?? leftPaneRef.current?.offsetWidth ?? 400,
58329
+ tabIndex: 0,
58330
+ className: "absolute inset-0 cursor-col-resize border-x border-surface-800 hover:border-blue-500 focus:border-blue-500 focus:outline-none transition-colors",
58331
+ onMouseDown: (e) => {
58332
+ dragging.current = "request";
58333
+ dragStart.current = { x: e.clientX, w: leftPaneRef.current?.offsetWidth ?? requestPaneWidth ?? 400 };
58334
+ document.body.style.cursor = "col-resize";
58335
+ document.body.style.userSelect = "none";
57534
58336
  e.preventDefault();
57535
- const step = e.key === "ArrowLeft" ? -16 : 16;
57536
- const cur = leftPaneRef.current?.offsetWidth ?? requestPaneWidth ?? 400;
57537
- setRequestPaneWidth(Math.max(200, Math.min(window.innerWidth - 300, cur + step)));
57538
- }
57539
- },
57540
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(
57541
- "button",
57542
- {
57543
- onClick: () => setResponseOpen((v) => !v),
57544
- title: responseOpen ? t("Collapse response") : t("Expand response"),
57545
- className: "absolute top-1/2 -translate-y-1/2 left-1/2 -translate-x-1/2 w-4 h-8 flex items-center justify-center rounded opacity-0 group-hover:opacity-100 bg-surface-800 text-surface-400 hover:text-white transition-all text-xs z-10",
57546
- children: responseOpen ? "›" : "‹"
58337
+ },
58338
+ onKeyDown: (e) => {
58339
+ if (e.key === "ArrowLeft" || e.key === "ArrowRight") {
58340
+ e.preventDefault();
58341
+ const step = e.key === "ArrowLeft" ? -16 : 16;
58342
+ const cur = leftPaneRef.current?.offsetWidth ?? requestPaneWidth ?? 400;
58343
+ setRequestPaneWidth(Math.max(200, Math.min(window.innerWidth - 300, cur + step)));
58344
+ }
57547
58345
  }
57548
- )
57549
- }
57550
- ),
58346
+ }
58347
+ ),
58348
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
58349
+ "button",
58350
+ {
58351
+ onClick: () => setResponseOpen((v) => !v),
58352
+ title: responseOpen ? t("Collapse response") : t("Expand response"),
58353
+ className: "absolute top-1/2 -translate-y-1/2 left-1/2 -translate-x-1/2 w-4 h-8 flex items-center justify-center rounded opacity-0 group-hover:opacity-100 bg-surface-800 text-surface-400 hover:text-white transition-all text-xs z-10",
58354
+ children: responseOpen ? "›" : "‹"
58355
+ }
58356
+ )
58357
+ ] }),
57551
58358
  responseOpen && /* @__PURE__ */ jsxRuntimeExports.jsx(
57552
58359
  "div",
57553
58360
  {