@testsmith/api-spector 0.8.8 → 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-TklsnkDw.js","./codemirror-BKmwMUlV.js","./ajv-CJPwFjiP.js","./SoapEditor-CllZqWyv.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 = {};
@@ -12087,7 +12087,7 @@ function reIdFolderTree(root2, mapRequestId) {
12087
12087
  root2.folders.forEach((sub) => reIdFolderTree(sub, mapRequestId));
12088
12088
  }
12089
12089
  function cloneAndReId(folder2, mapRequestId) {
12090
- const cloned = structuredClone(folder2);
12090
+ const cloned = JSON.parse(JSON.stringify(folder2));
12091
12091
  reIdFolderTree(cloned, mapRequestId);
12092
12092
  return cloned;
12093
12093
  }
@@ -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-TklsnkDw.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-CllZqWyv.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 }
@@ -38617,6 +39255,12 @@ function renderInline(text, keyBase) {
38617
39255
  return /* @__PURE__ */ jsxRuntimeExports.jsx(React.Fragment, { children: part }, key);
38618
39256
  });
38619
39257
  }
39258
+ function splitRow(line) {
39259
+ let s = line.trim();
39260
+ if (s.startsWith("|")) s = s.slice(1);
39261
+ if (s.endsWith("|")) s = s.slice(0, -1);
39262
+ return s.split("|").map((c) => c.trim());
39263
+ }
38620
39264
  function renderMarkdown(md) {
38621
39265
  const lines = md.replaceAll("\r\n", "\n").split("\n");
38622
39266
  const blocks = [];
@@ -38675,6 +39319,22 @@ function renderMarkdown(md) {
38675
39319
  );
38676
39320
  continue;
38677
39321
  }
39322
+ if (line.includes("|") && i + 1 < lines.length && /^\s*\|?\s*:?-+:?\s*(\|\s*:?-+:?\s*)+\|?\s*$/.test(lines[i + 1])) {
39323
+ const header2 = splitRow(line);
39324
+ i += 2;
39325
+ const rows = [];
39326
+ while (i < lines.length && lines[i].includes("|") && lines[i].trim() !== "") {
39327
+ rows.push(splitRow(lines[i]));
39328
+ i++;
39329
+ }
39330
+ blocks.push(
39331
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "overflow-x-auto my-1", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("table", { className: "border-collapse text-xs", children: [
39332
+ /* @__PURE__ */ jsxRuntimeExports.jsx("thead", { children: /* @__PURE__ */ jsxRuntimeExports.jsx("tr", { children: header2.map((c, ci) => /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "border border-surface-700 bg-surface-800 px-2 py-1 text-left font-semibold text-surface-200 whitespace-nowrap", children: renderInline(c, k()) }, ci)) }) }),
39333
+ /* @__PURE__ */ jsxRuntimeExports.jsx("tbody", { children: rows.map((r, ri) => /* @__PURE__ */ jsxRuntimeExports.jsx("tr", { children: header2.map((_, ci) => /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "border border-surface-700 px-2 py-1 align-top text-surface-300", children: renderInline(r[ci] ?? "", k()) }, ci)) }, ri)) })
39334
+ ] }) }, k())
39335
+ );
39336
+ continue;
39337
+ }
38678
39338
  if (/^\s*[-*+]\s+/.test(line)) {
38679
39339
  const items = [];
38680
39340
  while (i < lines.length && /^\s*[-*+]\s+/.test(lines[i])) {
@@ -39152,6 +39812,39 @@ function VariablesTab({ request: request2 }) {
39152
39812
  if (name in requestVars) return;
39153
39813
  addRow(name, valueOf(name) === "••••••••" ? "" : `{{${name}}}`);
39154
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
+ };
39155
39848
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-5 text-xs", children: [
39156
39849
  /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { children: [
39157
39850
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
@@ -39203,6 +39896,14 @@ function VariablesTab({ request: request2 }) {
39203
39896
  }
39204
39897
  ),
39205
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
+ ),
39206
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, {}) })
39207
39908
  ] }, i);
39208
39909
  }) })
@@ -39250,6 +39951,7 @@ function VariablesTab({ request: request2 }) {
39250
39951
  children: t("override")
39251
39952
  }
39252
39953
  ),
39954
+ locForScope(scope, name) && /* @__PURE__ */ jsxRuntimeExports.jsx(MoveVariableMenu, { from: locForScope(scope, name), name, onMoved: reseedRows }),
39253
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] })
39254
39956
  ] }, name);
39255
39957
  }) })
@@ -41652,6 +42354,7 @@ function RequestBuilder({ request: request2 }) {
41652
42354
  ) : /* @__PURE__ */ jsxRuntimeExports.jsxs(
41653
42355
  "select",
41654
42356
  {
42357
+ "aria-label": t("HTTP method"),
41655
42358
  value: METHODS.includes(request2.method) ? request2.method : "__current__",
41656
42359
  onChange: (e) => {
41657
42360
  if (e.target.value === "__custom__") setCustomVerb(true);
@@ -43806,8 +44509,8 @@ function ResponseViewer() {
43806
44509
  " KB"
43807
44510
  ] })
43808
44511
  ] }),
43809
- /* @__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: [
43810
- 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")) }),
43811
44514
  /* @__PURE__ */ jsxRuntimeExports.jsx(
43812
44515
  OverflowMenu,
43813
44516
  {
@@ -44012,7 +44715,7 @@ function ResponseViewer() {
44012
44715
  {
44013
44716
  value: jqResult ?? "",
44014
44717
  theme: oneDark,
44015
- extensions: [json()],
44718
+ extensions: [json(), ...cmLabel(t("Filtered response"))],
44016
44719
  readOnly: true,
44017
44720
  basicSetup: { lineNumbers: true, foldGutter: true }
44018
44721
  }
@@ -44036,7 +44739,7 @@ function ResponseViewer() {
44036
44739
  {
44037
44740
  value: displayBody,
44038
44741
  theme: oneDark,
44039
- extensions: isJson ? [json()] : isXml ? [xml()] : [],
44742
+ extensions: [...isJson ? [json()] : isXml ? [xml()] : [], ...cmLabel(t("Response body"))],
44040
44743
  readOnly: true,
44041
44744
  basicSetup: { lineNumbers: true, foldGutter: true }
44042
44745
  }
@@ -45499,7 +46202,6 @@ function HistoryRow({
45499
46202
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(
45500
46203
  "div",
45501
46204
  {
45502
- role: "button",
45503
46205
  tabIndex: 0,
45504
46206
  onClick: onSelect,
45505
46207
  onKeyDown: (e) => {
@@ -45630,7 +46332,7 @@ function WelcomeScreen() {
45630
46332
  /* @__PURE__ */ jsxRuntimeExports.jsxs("h1", { className: "text-2xl font-semibold mb-1", children: [
45631
46333
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--wordmark-muted)" }, children: "API" }),
45632
46334
  " ",
45633
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#6aa3c8" }, children: "Spector" })
46335
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--wordmark-accent)" }, children: "Spector" })
45634
46336
  ] }),
45635
46337
  /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] mb-3", style: { color: "var(--text-muted)" }, children: [
45636
46338
  t("by"),
@@ -45640,13 +46342,13 @@ function WelcomeScreen() {
45640
46342
  {
45641
46343
  onClick: () => window.electron.openExternal("https://testsmith.io"),
45642
46344
  className: "hover:underline focus:outline-none",
45643
- style: { color: "#6aa3c8" },
46345
+ style: { color: "var(--wordmark-accent)" },
45644
46346
  children: "Testsmith"
45645
46347
  }
45646
46348
  )
45647
46349
  ] }),
45648
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.") }),
45649
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] mt-3", style: { color: "var(--text-muted)" }, children: t("version :version", { version: "0.8.8" }) })
46351
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] mt-3", style: { color: "var(--text-muted)" }, children: t("version :version", { version: "0.9.0" }) })
45650
46352
  ] }),
45651
46353
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3 w-64", children: [
45652
46354
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -45677,7 +46379,7 @@ function WelcomeScreen() {
45677
46379
  onKeyDown: (e) => {
45678
46380
  if (e.key === "Enter") openFromGit();
45679
46381
  },
45680
- placeholder: "https://github.com/owner/repo",
46382
+ placeholder: "https://github.com/owner/repo or git@host:owner/repo.git",
45681
46383
  autoFocus: true,
45682
46384
  disabled: busy || gitBusy,
45683
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"
@@ -46149,7 +46851,7 @@ function EnvironmentEditor({ onClose }) {
46149
46851
  placeholder: t("Environment name")
46150
46852
  }
46151
46853
  ),
46152
- /* @__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: "×" })
46153
46855
  ] }),
46154
46856
  nameError && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-red-400 mt-1", children: nameError }),
46155
46857
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 mt-2", children: [
@@ -46273,14 +46975,24 @@ function EnvironmentEditor({ onClose }) {
46273
46975
  )
46274
46976
  ] })
46275
46977
  ] }),
46276
- /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-2 py-1.5", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
46277
- "button",
46278
- {
46279
- onClick: () => removeVar(idx),
46280
- className: "text-surface-400 hover:text-red-400 opacity-0 group-hover:opacity-100 transition-all",
46281
- children: "×"
46282
- }
46283
- ) })
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
+ ] }) })
46284
46996
  ] }),
46285
46997
  /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { children: [
46286
46998
  /* @__PURE__ */ jsxRuntimeExports.jsx("td", {}),
@@ -46450,6 +47162,7 @@ function EnvironmentBar({ inline = false }) {
46450
47162
  {
46451
47163
  value: activeEnvironmentId ?? "",
46452
47164
  onChange: (e) => handleEnvChange(e.target.value || null),
47165
+ "aria-label": t("Active environment"),
46453
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]",
46454
47167
  style: { color: "var(--text-primary)" },
46455
47168
  children: [
@@ -46871,6 +47584,7 @@ function WorkspaceSettingsModal({ onClose, initialTab }) {
46871
47584
  {
46872
47585
  value: defaultEnvironment,
46873
47586
  onChange: (e) => setDefaultEnvironment(e.target.value),
47587
+ "aria-label": t("Default environment"),
46874
47588
  className: "bg-surface-800 border border-surface-700 rounded px-2.5 py-1.5 focus:outline-none focus:border-blue-500",
46875
47589
  children: [
46876
47590
  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: t("(none)") }),
@@ -46887,6 +47601,7 @@ function WorkspaceSettingsModal({ onClose, initialTab }) {
46887
47601
  {
46888
47602
  value: defaultRequestTab,
46889
47603
  onChange: (e) => setDefaultRequestTab(e.target.value),
47604
+ "aria-label": t("Default request tab"),
46890
47605
  className: "bg-surface-800 border border-surface-700 rounded px-2.5 py-1.5 focus:outline-none focus:border-blue-500",
46891
47606
  children: [
46892
47607
  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "docs", children: t("Docs") }),
@@ -46958,6 +47673,7 @@ function WorkspaceSettingsModal({ onClose, initialTab }) {
46958
47673
  {
46959
47674
  value: locale,
46960
47675
  onChange: (e) => setLocale(e.target.value),
47676
+ "aria-label": t("Language"),
46961
47677
  className: "bg-surface-800 hover:bg-surface-700 text-surface-300 text-xs rounded py-1.5 px-2 outline-none",
46962
47678
  children: Object.entries(LOCALES).map(([code, name]) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: code, children: name }, code))
46963
47679
  }
@@ -47283,6 +47999,7 @@ function WorkspaceSettingsModal({ onClose, initialTab }) {
47283
47999
  {
47284
48000
  value: vAuthMethod,
47285
48001
  onChange: (e) => setVAuthMethod(e.target.value),
48002
+ "aria-label": t("Auth method"),
47286
48003
  className: "bg-surface-800 border border-surface-700 rounded px-2.5 py-1.5 focus:outline-none focus:border-blue-500",
47287
48004
  children: [
47288
48005
  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "token", children: t("Token / OIDC") }),
@@ -47342,6 +48059,7 @@ function WorkspaceSettingsModal({ onClose, initialTab }) {
47342
48059
  {
47343
48060
  value: vKvVersion,
47344
48061
  onChange: (e) => setVKvVersion(e.target.value),
48062
+ "aria-label": t("KV version"),
47345
48063
  className: "bg-surface-800 border border-surface-700 rounded px-2.5 py-1.5 focus:outline-none focus:border-blue-500",
47346
48064
  children: [
47347
48065
  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "auto", children: "auto" }),
@@ -47395,6 +48113,7 @@ function WorkspaceSettingsModal({ onClose, initialTab }) {
47395
48113
  value: azVault,
47396
48114
  onChange: (e) => setAzVault(e.target.value),
47397
48115
  placeholder: "acme-kv",
48116
+ "aria-label": t("Azure vault"),
47398
48117
  className: `${inputCls$1} placeholder-surface-600`
47399
48118
  }
47400
48119
  )
@@ -47406,6 +48125,7 @@ function WorkspaceSettingsModal({ onClose, initialTab }) {
47406
48125
  {
47407
48126
  value: azTenantId,
47408
48127
  onChange: (e) => setAzTenantId(e.target.value),
48128
+ "aria-label": t("Tenant id"),
47409
48129
  className: inputCls$1
47410
48130
  }
47411
48131
  )
@@ -47417,6 +48137,7 @@ function WorkspaceSettingsModal({ onClose, initialTab }) {
47417
48137
  {
47418
48138
  value: azClientId,
47419
48139
  onChange: (e) => setAzClientId(e.target.value),
48140
+ "aria-label": t("Client id"),
47420
48141
  className: inputCls$1
47421
48142
  }
47422
48143
  )
@@ -48665,7 +49386,7 @@ function Toolbar({ onOpenDocs: _onOpenDocs }) {
48665
49386
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-semibold tracking-wide", children: [
48666
49387
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--wordmark-muted)" }, children: "API" }),
48667
49388
  " ",
48668
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#6aa3c8" }, children: "Spector" })
49389
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--wordmark-accent)" }, children: "Spector" })
48669
49390
  ] }),
48670
49391
  /* @__PURE__ */ jsxRuntimeExports.jsx(
48671
49392
  "button",
@@ -48917,18 +49638,18 @@ function buildHtmlReport(results, summary2, meta = {}) {
48917
49638
  :root {
48918
49639
  --bg: #0f1117; --bg-surface: #161b22; --bg-panel: #0d1117;
48919
49640
  --border: #21262d; --border-hover:#30363d;
48920
- --text: #c9d1d9; --text-bright: #e6edf3; --text-muted: #8b949e; --text-dim: #484f58;
49641
+ --text: #c9d1d9; --text-bright: #e6edf3; --text-muted: #8b949e; --text-dim: #818992;
48921
49642
  --green: #3fb950; --red: #f85149; --amber: #d29922; --blue: #79c0ff;
48922
49643
  --badge-pass-bg: #0d3a1e; --badge-fail-bg: #3d1014; --badge-err-bg: #3d2a00; --badge-skip-bg: #21262d;
48923
49644
  --hook-before-border: #7c3aed; --hook-after-border: #0e7490;
48924
49645
  --hook-before-bg: #4c1d95; --hook-before-fg: #c4b5fd;
48925
49646
  --hook-after-bg: #164e63; --hook-after-fg: #67e8f9;
48926
- --link: #3d7fb2;
49647
+ --link: #58a6ff;
48927
49648
  }
48928
49649
  html.light {
48929
49650
  --bg: #ffffff; --bg-surface: #f6f8fa; --bg-panel: #ffffff;
48930
49651
  --border: #d0d7de; --border-hover:#c4c9cf;
48931
- --text: #1f2328; --text-bright: #1f2328; --text-muted: #656d76; --text-dim: #8b949e;
49652
+ --text: #1f2328; --text-bright: #1f2328; --text-muted: #656d76; --text-dim: #6b7280;
48932
49653
  --green: #1a7f37; --red: #cf222e; --amber: #9a6700; --blue: #0969da;
48933
49654
  --badge-pass-bg: #dafbe1; --badge-fail-bg: #ffebe9; --badge-err-bg: #fff8c5; --badge-skip-bg: #f6f8fa;
48934
49655
  --hook-before-border: #8b5cf6; --hook-after-border: #06b6d4;
@@ -50534,7 +51255,7 @@ function toCSV(ds) {
50534
51255
  function parseCSV(text) {
50535
51256
  const lines = text.trim().split(/\r?\n/).filter(Boolean);
50536
51257
  if (lines.length === 0) return { columns: [], rows: [] };
50537
- function splitRow(line) {
51258
+ function splitRow2(line) {
50538
51259
  const cells = [];
50539
51260
  let cur = "";
50540
51261
  let inQuote = false;
@@ -50555,8 +51276,8 @@ function parseCSV(text) {
50555
51276
  cells.push(cur.trim());
50556
51277
  return cells;
50557
51278
  }
50558
- const columns = splitRow(lines[0]);
50559
- const rows = lines.slice(1).map(splitRow);
51279
+ const columns = splitRow2(lines[0]);
51280
+ const rows = lines.slice(1).map(splitRow2);
50560
51281
  return { columns, rows };
50561
51282
  }
50562
51283
  function DataSetEditor({ ds, onChange, exportName, scopeLabel = "collection" }) {
@@ -50715,6 +51436,13 @@ function CollectionPanel() {
50715
51436
  const disabled = Object.fromEntries(rows.filter((r) => !r.enabled && r.key.trim()).map((r) => [r.key.trim(), r.value]));
50716
51437
  updateCollectionVariables(activeCollectionId, variables, disabled);
50717
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
+ }
50718
51446
  if (!activeCollectionId) {
50719
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") });
50720
51448
  }
@@ -50795,7 +51523,17 @@ function CollectionPanel() {
50795
51523
  activeTab === "data" && /* @__PURE__ */ jsxRuntimeExports.jsx(DataSetEditor, { ds, onChange: setDs, exportName: col.name, scopeLabel: "collection" }),
50796
51524
  activeTab === "variables" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2 text-xs", children: [
50797
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}}" }) }),
50798
- /* @__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
+ ),
50799
51537
  /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-surface-600 text-[11px]", children: [
50800
51538
  t("Scripts can also set these at runtime via"),
50801
51539
  " ",
@@ -50837,6 +51575,13 @@ function FolderPanel() {
50837
51575
  const variablesDisabled = Object.fromEntries(rows.filter((r) => !r.enabled && r.key.trim()).map((r) => [r.key.trim(), r.value]));
50838
51576
  updateFolder(cid, folder2.id, { variables, variablesDisabled });
50839
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
+ }
50840
51585
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col h-full", children: [
50841
51586
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-6 py-4 border-b border-surface-800 flex-shrink-0 flex items-center justify-between", children: [
50842
51587
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
@@ -50887,7 +51632,17 @@ function FolderPanel() {
50887
51632
  activeTab === "data" && /* @__PURE__ */ jsxRuntimeExports.jsx(DataSetEditor, { ds, onChange: (next) => updateFolder(cid, folder2.id, { dataSet: next }), exportName: folder2.name, scopeLabel: "folder" }),
50888
51633
  activeTab === "variables" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2", children: [
50889
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}}" }) }),
50890
- /* @__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
+ )
50891
51646
  ] })
50892
51647
  ] })
50893
51648
  ] });
@@ -53584,7 +54339,7 @@ function ConflictEditor({ path, onClose, onResolved }) {
53584
54339
  children: t("Edit manually")
53585
54340
  }
53586
54341
  ),
53587
- /* @__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: "×" })
53588
54343
  ] })
53589
54344
  ] }),
53590
54345
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto min-h-0", children: [
@@ -53897,7 +54652,6 @@ function ChangesTab({ status, onRefresh }) {
53897
54652
  "div",
53898
54653
  {
53899
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" : ""}`,
53900
- role: "button",
53901
54655
  tabIndex: 0,
53902
54656
  onClick: () => showDiff(f, true),
53903
54657
  onKeyDown: onActivateKey(() => showDiff(f, true)),
@@ -53937,7 +54691,6 @@ function ChangesTab({ status, onRefresh }) {
53937
54691
  "div",
53938
54692
  {
53939
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" : ""}`,
53940
- role: "button",
53941
54694
  tabIndex: 0,
53942
54695
  onClick: () => showDiff(f, false),
53943
54696
  onKeyDown: onActivateKey(() => showDiff(f, false)),
@@ -53967,7 +54720,6 @@ function ChangesTab({ status, onRefresh }) {
53967
54720
  "div",
53968
54721
  {
53969
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" : ""}`,
53970
- role: "button",
53971
54723
  tabIndex: 0,
53972
54724
  onClick: () => showDiff({ path, status: "modified" }, false),
53973
54725
  onKeyDown: onActivateKey(() => showDiff({ path, status: "modified" }, false)),
@@ -55152,6 +55904,9 @@ function pretty(v) {
55152
55904
  return esc(String(v));
55153
55905
  }
55154
55906
  }
55907
+ function headerLines(h) {
55908
+ return Object.entries(h).map(([k, v]) => `${k}: ${v}`).join("\n");
55909
+ }
55155
55910
  const STATUS_CLS = {
55156
55911
  passed: "badge-pass",
55157
55912
  failed: "badge-fail",
@@ -55169,8 +55924,18 @@ function blockDetail(b) {
55169
55924
  ).join("");
55170
55925
  parts.push(`<div class="section-label">Tests</div><div class="tests-wrap">${rows}</div>`);
55171
55926
  }
55172
- if (b.type === "request" && b.resolvedUrl) {
55173
- 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>');
55174
55939
  }
55175
55940
  if (b.type === "log" && b.message) {
55176
55941
  parts.push(`<div class="section-label">Message</div><pre class="code-block">${esc(b.message)}</pre>`);
@@ -55380,7 +56145,10 @@ function useFlowRunner() {
55380
56145
  iteration: b.iteration,
55381
56146
  atMs: b.atMs,
55382
56147
  message: b.message,
55383
- value: b.display
56148
+ value: b.display,
56149
+ method: b.method,
56150
+ resolvedUrl: b.resolvedUrl,
56151
+ http: b.http
55384
56152
  }));
55385
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 });
55386
56154
  setState((prev) => ({
@@ -55835,6 +56603,7 @@ function AddBlockMenu({ onAdd: onAdd2 }) {
55835
56603
  ] })
55836
56604
  ] });
55837
56605
  }
56606
+ const headerText = (h) => Object.entries(h).map(([k, v]) => `${k}: ${v}`).join("\n");
55838
56607
  const LOG_ICON = {
55839
56608
  passed: "✓",
55840
56609
  failed: "✗",
@@ -55871,6 +56640,15 @@ function formatLogText(log) {
55871
56640
  function BottomPanel({ runner, flowName, problems, onFocusBlock, tab, setTab }) {
55872
56641
  const t = useT();
55873
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]);
55874
56652
  const varEntries = Object.entries(variables);
55875
56653
  const dataEntries = Object.entries(data).filter(([k, v]) => typeof v === "object" && v !== null || !(k in variables));
55876
56654
  const hasVars = varEntries.length > 0 || dataEntries.length > 0;
@@ -55945,24 +56723,63 @@ function BottomPanel({ runner, flowName, problems, onFocusBlock, tab, setTab })
55945
56723
  ": ",
55946
56724
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-300 break-all", children: typeof e.value === "string" ? e.value : JSON.stringify(e.value) })
55947
56725
  ] }, i);
55948
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-baseline gap-2", children: [
55949
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-600 w-14 shrink-0 text-right", children: at }),
55950
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: LOG_ICON_CLS[e.status ?? "done"], children: LOG_ICON[e.status ?? "done"] ?? "•" }),
55951
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-300", children: [
55952
- e.label ?? e.type,
55953
- e.iteration != null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-600", children: [
55954
- " #",
55955
- e.iteration
55956
- ] })
55957
- ] }),
55958
- e.httpStatus != null && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: e.httpStatus < 400 ? "text-emerald-400" : "text-red-400", children: e.httpStatus }),
55959
- e.durationMs != null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-600", children: [
55960
- e.durationMs,
55961
- "ms"
55962
- ] }),
55963
- e.error && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-red-400 break-all", children: [
55964
- "— ",
55965
- 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") })
55966
56783
  ] })
55967
56784
  ] }, i);
55968
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: [
@@ -56850,17 +57667,17 @@ function ActivityBarBtn({
56850
57667
  dataTour
56851
57668
  }) {
56852
57669
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative group/ab", "data-tour": dataTour, children: [
56853
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
57670
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
56854
57671
  "button",
56855
57672
  {
56856
57673
  onClick,
57674
+ "aria-label": title,
57675
+ "aria-pressed": active2,
56857
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"}`,
56858
- children: [
56859
- children2,
56860
- 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 })
56861
- ]
57677
+ children: children2
56862
57678
  }
56863
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 }),
56864
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 }) })
56865
57682
  ] });
56866
57683
  }
@@ -56885,35 +57702,45 @@ const TabRow = React.memo(function TabRow2({
56885
57702
  onContextMenu
56886
57703
  }) {
56887
57704
  const t = useT();
56888
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(
56889
- "div",
56890
- {
56891
- role: "button",
56892
- tabIndex: 0,
56893
- onClick: () => onActivate(tabId),
56894
- onKeyDown: onActivateKey(() => onActivate(tabId)),
56895
- onContextMenu: (e) => {
56896
- e.preventDefault();
56897
- onContextMenu(tabId, e.clientX, e.clientY);
56898
- },
56899
- 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"}`,
56900
- children: [
56901
- 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,
56902
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-xs truncate ${isActive ? "text-white" : ""}`, children: name }),
56903
- /* @__PURE__ */ jsxRuntimeExports.jsx(
56904
- "button",
56905
- {
56906
- onClick: (e) => {
56907
- e.stopPropagation();
56908
- onClose(tabId);
56909
- },
56910
- className: "ml-auto opacity-0 group-hover:opacity-100 shrink-0 text-surface-600 hover:text-white transition-all leading-none",
56911
- title: t("Close tab"),
56912
- children: "×"
56913
- }
56914
- )
56915
- ]
56916
- }
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
+ )
56917
57744
  );
56918
57745
  });
56919
57746
  function App() {
@@ -57175,18 +58002,18 @@ function App() {
57175
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: [
57176
58003
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--wordmark-muted)" }, children: "API" }),
57177
58004
  " ",
57178
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#6aa3c8" }, children: "Spector" }),
57179
- /* @__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: [
57180
58007
  "v",
57181
- "0.8.8"
58008
+ "0.9.0"
57182
58009
  ] }),
57183
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "mx-2 opacity-30", children: "·" }),
58010
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "mx-2 opacity-30", "aria-hidden": "true", children: "·" }),
57184
58011
  /* @__PURE__ */ jsxRuntimeExports.jsx(
57185
58012
  "button",
57186
58013
  {
57187
58014
  onClick: () => window.electron.openExternal("https://testsmith.io"),
57188
- className: "no-drag text-[10px] font-normal opacity-60 hover:opacity-100 hover:underline focus:outline-none transition-opacity",
57189
- style: { color: "#6aa3c8" },
58015
+ className: "no-drag text-[10px] font-normal hover:underline focus:outline-none",
58016
+ style: { color: "var(--wordmark-accent)" },
57190
58017
  children: "testsmith.io"
57191
58018
  }
57192
58019
  )
@@ -57490,42 +58317,44 @@ function App() {
57490
58317
  children: /* @__PURE__ */ jsxRuntimeExports.jsx(RequestBuilder, { request: activeRequest })
57491
58318
  }
57492
58319
  ),
57493
- /* @__PURE__ */ jsxRuntimeExports.jsx(
57494
- "div",
57495
- {
57496
- role: "separator",
57497
- "aria-orientation": "vertical",
57498
- "aria-label": "Resize request pane",
57499
- "aria-valuemin": 200,
57500
- "aria-valuenow": requestPaneWidth ?? leftPaneRef.current?.offsetWidth ?? 400,
57501
- tabIndex: 0,
57502
- 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",
57503
- onMouseDown: (e) => {
57504
- dragging.current = "request";
57505
- dragStart.current = { x: e.clientX, w: leftPaneRef.current?.offsetWidth ?? requestPaneWidth ?? 400 };
57506
- document.body.style.cursor = "col-resize";
57507
- document.body.style.userSelect = "none";
57508
- e.preventDefault();
57509
- },
57510
- onKeyDown: (e) => {
57511
- 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";
57512
58336
  e.preventDefault();
57513
- const step = e.key === "ArrowLeft" ? -16 : 16;
57514
- const cur = leftPaneRef.current?.offsetWidth ?? requestPaneWidth ?? 400;
57515
- setRequestPaneWidth(Math.max(200, Math.min(window.innerWidth - 300, cur + step)));
57516
- }
57517
- },
57518
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(
57519
- "button",
57520
- {
57521
- onClick: () => setResponseOpen((v) => !v),
57522
- title: responseOpen ? t("Collapse response") : t("Expand response"),
57523
- 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",
57524
- 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
+ }
57525
58345
  }
57526
- )
57527
- }
57528
- ),
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
+ ] }),
57529
58358
  responseOpen && /* @__PURE__ */ jsxRuntimeExports.jsx(
57530
58359
  "div",
57531
58360
  {