@apicircle/core 1.0.9 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/{chunk-L5DQT7V6.js → chunk-T6A4ICRL.js} +5 -5
- package/dist/chunk-T6A4ICRL.js.map +1 -0
- package/dist/index.cjs +834 -95
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +210 -11
- package/dist/index.d.ts +210 -11
- package/dist/index.js +806 -83
- package/dist/index.js.map +1 -1
- package/dist/{patches-h_K1VcZR.d.cts → patches-B3VGNVgf.d.cts} +53 -1
- package/dist/{patches-h_K1VcZR.d.ts → patches-B3VGNVgf.d.ts} +53 -1
- package/dist/workspace/file-backed.cjs +4 -4
- package/dist/workspace/file-backed.cjs.map +1 -1
- package/dist/workspace/file-backed.d.cts +5 -1
- package/dist/workspace/file-backed.d.ts +5 -1
- package/dist/workspace/file-backed.js +1 -1
- package/dist/workspace/registry.cjs +13 -33
- package/dist/workspace/registry.cjs.map +1 -1
- package/dist/workspace/registry.d.cts +13 -26
- package/dist/workspace/registry.d.ts +13 -26
- package/dist/workspace/registry.js +9 -30
- package/dist/workspace/registry.js.map +1 -1
- package/package.json +3 -2
- package/dist/chunk-L5DQT7V6.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -22,31 +22,35 @@ var src_exports = {};
|
|
|
22
22
|
__export(src_exports, {
|
|
23
23
|
ANONYMOUS_ACTOR: () => ANONYMOUS_ACTOR,
|
|
24
24
|
APICIRCLE_FOLDER_EXPORT_FORMAT: () => APICIRCLE_FOLDER_EXPORT_FORMAT,
|
|
25
|
-
ATTACHMENTS_DIR: () => ATTACHMENTS_DIR,
|
|
26
25
|
DESKTOP_APP_ORIGIN: () => DESKTOP_APP_ORIGIN,
|
|
27
26
|
EMPTY_UNPUSHED_SUMMARY: () => EMPTY_UNPUSHED_SUMMARY,
|
|
28
27
|
HTTP_HEADERS_MAP: () => HTTP_HEADERS_MAP,
|
|
29
28
|
OAuth2TokenError: () => OAuth2TokenError,
|
|
30
29
|
PlanRunDeniedError: () => PlanRunDeniedError,
|
|
30
|
+
REGISTRY_JSON_PATH: () => REGISTRY_JSON_PATH,
|
|
31
31
|
RemoteWorkspaceParseError: () => RemoteWorkspaceParseError,
|
|
32
32
|
TRANSFORM_FORMAT_LABELS: () => TRANSFORM_FORMAT_LABELS,
|
|
33
33
|
WORKSPACE_DIR: () => WORKSPACE_DIR,
|
|
34
|
-
|
|
34
|
+
appendReleaseEntry: () => appendReleaseEntry,
|
|
35
35
|
applyAuth: () => applyAuth,
|
|
36
36
|
applyAwsSigV4: () => applyAwsSigV4,
|
|
37
37
|
applyContentTypeForBodyType: () => applyContentTypeForBodyType,
|
|
38
|
+
applyLinkedEnvironmentOverrides: () => applyLinkedEnvironmentOverrides,
|
|
38
39
|
applyLinkedUpdate: () => applyLinkedUpdate,
|
|
39
40
|
applyMerge: () => applyMerge,
|
|
40
41
|
applyMutation: () => applyMutation,
|
|
41
42
|
applyPathParams: () => applyPathParams,
|
|
42
43
|
assertNoPlaintextCredentials: () => assertNoPlaintextCredentials,
|
|
43
44
|
attachmentPath: () => attachmentPath,
|
|
45
|
+
attachmentsDir: () => attachmentsDir,
|
|
44
46
|
buildAuthorizeUrl: () => buildAuthorizeUrl,
|
|
45
47
|
buildAutoHeaders: () => buildAutoHeaders,
|
|
46
48
|
buildDigestAuthHeader: () => buildDigestAuthHeader,
|
|
47
49
|
buildHawkAuthHeader: () => buildHawkAuthHeader,
|
|
50
|
+
buildLinkedSnapshot: () => buildLinkedSnapshot,
|
|
48
51
|
buildNtlmType1Negotiate: () => buildNtlmType1Negotiate,
|
|
49
52
|
buildNtlmType3Authenticate: () => buildNtlmType3Authenticate,
|
|
53
|
+
buildReleaseEntry: () => buildReleaseEntry,
|
|
50
54
|
buildRequest: () => buildRequest,
|
|
51
55
|
buildScope: () => buildScope,
|
|
52
56
|
collectAttachmentSlots: () => collectAttachmentSlots,
|
|
@@ -60,6 +64,7 @@ __export(src_exports, {
|
|
|
60
64
|
composeUrl: () => composeUrl,
|
|
61
65
|
composeUrlWithQuery: () => composeUrlWithQuery,
|
|
62
66
|
computeCodeChallenge: () => computeCodeChallenge,
|
|
67
|
+
computeRequestOverridePatch: () => computeRequestOverridePatch,
|
|
63
68
|
computeThreeWayDiff: () => computeThreeWayDiff,
|
|
64
69
|
computeTransformSavings: () => computeTransformSavings,
|
|
65
70
|
decryptString: () => decryptString,
|
|
@@ -72,6 +77,7 @@ __export(src_exports, {
|
|
|
72
77
|
exportKey: () => exportKey,
|
|
73
78
|
extractContext: () => extractContext,
|
|
74
79
|
fetchOAuth2Token: () => fetchOAuth2Token,
|
|
80
|
+
fetchRemoteWorkspaceJson: () => fetchRemoteWorkspaceJson,
|
|
75
81
|
findPathPlaceholders: () => findPathPlaceholders,
|
|
76
82
|
generateAesKey: () => generateAesKey,
|
|
77
83
|
generateCodeVerifier: () => generateCodeVerifier,
|
|
@@ -89,14 +95,18 @@ __export(src_exports, {
|
|
|
89
95
|
hasUnpushedChanges: () => hasUnpushedChanges,
|
|
90
96
|
importApicircleFolderInto: () => importApicircleFolderInto,
|
|
91
97
|
importKey: () => importKey,
|
|
98
|
+
initSecretCrypto: () => initSecretCrypto,
|
|
92
99
|
isApicircleEnvironment: () => isApicircleEnvironment,
|
|
93
100
|
isApicircleFolderExport: () => isApicircleFolderExport,
|
|
94
101
|
isDesktop: () => isDesktop,
|
|
102
|
+
isEmptyOverridePatch: () => isEmptyOverridePatch,
|
|
95
103
|
isInsomniaExport: () => isInsomniaExport,
|
|
96
104
|
isPostmanEnvironment: () => isPostmanEnvironment,
|
|
97
105
|
isPostmanV2Collection: () => isPostmanV2Collection,
|
|
98
106
|
isValidSemver: () => isValidSemver,
|
|
107
|
+
ledgerFromProbe: () => ledgerFromProbe,
|
|
99
108
|
lookup: () => lookup,
|
|
109
|
+
mergeRequestOverride: () => mergeRequestOverride,
|
|
100
110
|
mergeWithAutoHeaders: () => mergeWithAutoHeaders,
|
|
101
111
|
normalizeContentType: () => normalizeContentType,
|
|
102
112
|
parseApicircleEnvironment: () => parseApicircleEnvironment,
|
|
@@ -107,12 +117,15 @@ __export(src_exports, {
|
|
|
107
117
|
parseDigestChallenge: () => parseDigestChallenge,
|
|
108
118
|
parseGraphqlSchema: () => parseGraphqlSchema,
|
|
109
119
|
parseInsomniaCollection: () => parseInsomniaCollection,
|
|
120
|
+
parseLinkedWorkspaceJson: () => parseLinkedWorkspaceJson,
|
|
110
121
|
parseNtlmType2Challenge: () => parseNtlmType2Challenge,
|
|
111
122
|
parsePostmanCollection: () => parsePostmanCollection,
|
|
112
123
|
parsePostmanEnvironment: () => parsePostmanEnvironment,
|
|
124
|
+
parseRegistryActiveId: () => parseRegistryActiveId,
|
|
113
125
|
parseSemver: () => parseSemver,
|
|
114
126
|
parseUrlQuery: () => parseUrlQuery,
|
|
115
127
|
parseWorkspaceJson: () => parseWorkspaceJson,
|
|
128
|
+
plaintextEnvMap: () => plaintextEnvMap,
|
|
116
129
|
pollDeviceFlow: () => pollDeviceFlow,
|
|
117
130
|
preSendValidation: () => preSendValidation,
|
|
118
131
|
previewLinkedUpdate: () => previewLinkedUpdate,
|
|
@@ -125,6 +138,7 @@ __export(src_exports, {
|
|
|
125
138
|
requestRunToExecutionResult: () => requestRunToExecutionResult,
|
|
126
139
|
resolveInheritedAuth: () => resolveInheritedAuth,
|
|
127
140
|
resolvePlanRef: () => resolvePlanRef,
|
|
141
|
+
resolveRequestForExecution: () => resolveRequestForExecution,
|
|
128
142
|
resolveString: () => resolveString,
|
|
129
143
|
resolveStringMap: () => resolveStringMap,
|
|
130
144
|
runAssertions: () => runAssertions,
|
|
@@ -146,7 +160,9 @@ __export(src_exports, {
|
|
|
146
160
|
toYaml: () => toYaml,
|
|
147
161
|
tokenizeCurl: () => tokenizeCurl,
|
|
148
162
|
tryParsePayload: () => tryParsePayload,
|
|
163
|
+
unlockSecretCrypto: () => unlockSecretCrypto,
|
|
149
164
|
validateBranchName: () => validateBranchName,
|
|
165
|
+
workspaceJsonPath: () => workspaceJsonPath,
|
|
150
166
|
yankRelease: () => yankRelease
|
|
151
167
|
});
|
|
152
168
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -1207,8 +1223,7 @@ async function importPkcs8(pem, algorithm) {
|
|
|
1207
1223
|
"JWT: PKCS#1 RSA PEM (`BEGIN RSA PRIVATE KEY`) is not supported. Convert with `openssl pkcs8 -topk8 -in key.pem -out pkcs8.pem -nocrypt`."
|
|
1208
1224
|
);
|
|
1209
1225
|
}
|
|
1210
|
-
const
|
|
1211
|
-
const body = envelope ? envelope[1] : pem;
|
|
1226
|
+
const body = extractPemBody(pem);
|
|
1212
1227
|
const stripped = body.replace(/\s+/g, "");
|
|
1213
1228
|
if (!stripped) {
|
|
1214
1229
|
throw new Error("JWT: PEM key is empty after stripping headers/whitespace");
|
|
@@ -1229,6 +1244,19 @@ async function importPkcs8(pem, algorithm) {
|
|
|
1229
1244
|
["sign"]
|
|
1230
1245
|
);
|
|
1231
1246
|
}
|
|
1247
|
+
function extractPemBody(pem) {
|
|
1248
|
+
const BEGIN = "-----BEGIN ";
|
|
1249
|
+
const END = "-----END ";
|
|
1250
|
+
const FENCE = "-----";
|
|
1251
|
+
const beginAt = pem.indexOf(BEGIN);
|
|
1252
|
+
if (beginAt === -1) return pem;
|
|
1253
|
+
const beginHeaderEnd = pem.indexOf(FENCE, beginAt + BEGIN.length);
|
|
1254
|
+
if (beginHeaderEnd === -1) return pem;
|
|
1255
|
+
const bodyStart = beginHeaderEnd + FENCE.length;
|
|
1256
|
+
const endAt = pem.indexOf(END, bodyStart);
|
|
1257
|
+
if (endAt === -1) return pem;
|
|
1258
|
+
return pem.slice(bodyStart, endAt);
|
|
1259
|
+
}
|
|
1232
1260
|
function base64UrlEncode(bytes) {
|
|
1233
1261
|
let s = "";
|
|
1234
1262
|
for (let i = 0; i < bytes.length; i++) s += String.fromCharCode(bytes[i]);
|
|
@@ -1683,6 +1711,10 @@ async function fetchOAuth2Token(args) {
|
|
|
1683
1711
|
if (args.extraParams) {
|
|
1684
1712
|
for (const [k, v] of Object.entries(args.extraParams)) body.set(k, v);
|
|
1685
1713
|
}
|
|
1714
|
+
const tokenUrlParsed = new URL(args.tokenUrl);
|
|
1715
|
+
if (tokenUrlParsed.protocol !== "https:" && tokenUrlParsed.protocol !== "http:") {
|
|
1716
|
+
throw new Error(`Token URL must use HTTP or HTTPS, got ${tokenUrlParsed.protocol}`);
|
|
1717
|
+
}
|
|
1686
1718
|
const response = await fetchImpl(args.tokenUrl, {
|
|
1687
1719
|
method: "POST",
|
|
1688
1720
|
headers,
|
|
@@ -2629,6 +2661,30 @@ function getVariableAutocomplete(text, cursorPosition, scope) {
|
|
|
2629
2661
|
);
|
|
2630
2662
|
}
|
|
2631
2663
|
|
|
2664
|
+
// src/request/resolveInheritedAuth.ts
|
|
2665
|
+
var NONE = { type: "none" };
|
|
2666
|
+
function resolveInheritedAuth({
|
|
2667
|
+
requestAuth,
|
|
2668
|
+
folderId,
|
|
2669
|
+
folders
|
|
2670
|
+
}) {
|
|
2671
|
+
if (requestAuth.type !== "inherit") return requestAuth;
|
|
2672
|
+
let cursor = folderId;
|
|
2673
|
+
const visited = /* @__PURE__ */ new Set();
|
|
2674
|
+
while (cursor !== null) {
|
|
2675
|
+
if (visited.has(cursor)) {
|
|
2676
|
+
break;
|
|
2677
|
+
}
|
|
2678
|
+
visited.add(cursor);
|
|
2679
|
+
const folder = folders[cursor];
|
|
2680
|
+
if (!folder) break;
|
|
2681
|
+
const auth = folder.auth;
|
|
2682
|
+
if (auth && auth.type !== "inherit" && auth.type !== "none") return auth;
|
|
2683
|
+
cursor = folder.parentId;
|
|
2684
|
+
}
|
|
2685
|
+
return NONE;
|
|
2686
|
+
}
|
|
2687
|
+
|
|
2632
2688
|
// src/request/preSendValidation.ts
|
|
2633
2689
|
var TYPED_BODY_CT = {
|
|
2634
2690
|
json: ["application/json", "application/ld+json", "application/vnd.api+json"],
|
|
@@ -2641,7 +2697,8 @@ function collectMissing(value, scope) {
|
|
|
2641
2697
|
}
|
|
2642
2698
|
function preSendValidation({
|
|
2643
2699
|
request,
|
|
2644
|
-
scope
|
|
2700
|
+
scope,
|
|
2701
|
+
folders
|
|
2645
2702
|
}) {
|
|
2646
2703
|
const warnings = [];
|
|
2647
2704
|
const blockers = [];
|
|
@@ -2716,29 +2773,43 @@ function preSendValidation({
|
|
|
2716
2773
|
});
|
|
2717
2774
|
}
|
|
2718
2775
|
}
|
|
2719
|
-
|
|
2776
|
+
let effectiveAuth = request.auth;
|
|
2777
|
+
let resolvedFromInherit = false;
|
|
2778
|
+
if (folders && effectiveAuth?.type === "inherit") {
|
|
2779
|
+
effectiveAuth = resolveInheritedAuth({
|
|
2780
|
+
requestAuth: { type: "inherit" },
|
|
2781
|
+
folderId: request.folderId,
|
|
2782
|
+
folders
|
|
2783
|
+
});
|
|
2784
|
+
resolvedFromInherit = true;
|
|
2785
|
+
}
|
|
2786
|
+
const auth = effectiveAuth;
|
|
2787
|
+
const inheritedNote = resolvedFromInherit ? " (resolved from folder-level auth)" : "";
|
|
2720
2788
|
if (auth) {
|
|
2721
2789
|
if (auth.type === "bearer" && !auth.token?.trim()) {
|
|
2722
|
-
blockers.push({
|
|
2790
|
+
blockers.push({
|
|
2791
|
+
kind: "auth-fields-missing",
|
|
2792
|
+
message: `Bearer token is empty.${inheritedNote}`
|
|
2793
|
+
});
|
|
2723
2794
|
} else if (auth.type === "basic") {
|
|
2724
2795
|
if (!auth.username?.trim() || !auth.password?.trim()) {
|
|
2725
2796
|
blockers.push({
|
|
2726
2797
|
kind: "auth-fields-missing",
|
|
2727
|
-
message:
|
|
2798
|
+
message: `Basic auth requires both username and password.${inheritedNote}`
|
|
2728
2799
|
});
|
|
2729
2800
|
}
|
|
2730
2801
|
} else if (auth.type === "api-key") {
|
|
2731
2802
|
if (!auth.key?.trim() || !auth.value?.trim()) {
|
|
2732
2803
|
blockers.push({
|
|
2733
2804
|
kind: "auth-fields-missing",
|
|
2734
|
-
message:
|
|
2805
|
+
message: `API key auth requires both name and value.${inheritedNote}`
|
|
2735
2806
|
});
|
|
2736
2807
|
}
|
|
2737
2808
|
} else if (auth.type === "custom-header") {
|
|
2738
2809
|
if (!auth.key?.trim()) {
|
|
2739
2810
|
blockers.push({
|
|
2740
2811
|
kind: "auth-fields-missing",
|
|
2741
|
-
message:
|
|
2812
|
+
message: `Custom header auth requires a header name.${inheritedNote}`
|
|
2742
2813
|
});
|
|
2743
2814
|
}
|
|
2744
2815
|
}
|
|
@@ -3125,6 +3196,15 @@ async function executeRequest(req, opts = {}) {
|
|
|
3125
3196
|
);
|
|
3126
3197
|
const redirectMode = isBrowserRuntime() ? "follow" : "manual";
|
|
3127
3198
|
let currentUrl = builtRequest.url;
|
|
3199
|
+
try {
|
|
3200
|
+
const parsedUrl = new URL(currentUrl);
|
|
3201
|
+
if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
|
|
3202
|
+
throw new Error(`Unsupported URL scheme: ${parsedUrl.protocol}`);
|
|
3203
|
+
}
|
|
3204
|
+
} catch (e) {
|
|
3205
|
+
if (e instanceof Error && e.message.startsWith("Unsupported URL scheme")) throw e;
|
|
3206
|
+
throw new Error(`Invalid request URL: ${currentUrl}`);
|
|
3207
|
+
}
|
|
3128
3208
|
let currentHeaders = { ...builtRequest.headers };
|
|
3129
3209
|
let currentMethod = builtRequest.method;
|
|
3130
3210
|
let currentBody = builtRequest.body;
|
|
@@ -3423,30 +3503,6 @@ function base64UrlEncode2(bytes) {
|
|
|
3423
3503
|
return btoa(s).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
3424
3504
|
}
|
|
3425
3505
|
|
|
3426
|
-
// src/request/resolveInheritedAuth.ts
|
|
3427
|
-
var NONE = { type: "none" };
|
|
3428
|
-
function resolveInheritedAuth({
|
|
3429
|
-
requestAuth,
|
|
3430
|
-
folderId,
|
|
3431
|
-
folders
|
|
3432
|
-
}) {
|
|
3433
|
-
if (requestAuth.type !== "inherit") return requestAuth;
|
|
3434
|
-
let cursor = folderId;
|
|
3435
|
-
const visited = /* @__PURE__ */ new Set();
|
|
3436
|
-
while (cursor !== null) {
|
|
3437
|
-
if (visited.has(cursor)) {
|
|
3438
|
-
break;
|
|
3439
|
-
}
|
|
3440
|
-
visited.add(cursor);
|
|
3441
|
-
const folder = folders[cursor];
|
|
3442
|
-
if (!folder) break;
|
|
3443
|
-
const auth = folder.auth;
|
|
3444
|
-
if (auth && auth.type !== "inherit" && auth.type !== "none") return auth;
|
|
3445
|
-
cursor = folder.parentId;
|
|
3446
|
-
}
|
|
3447
|
-
return NONE;
|
|
3448
|
-
}
|
|
3449
|
-
|
|
3450
3506
|
// src/request/parseCurl.ts
|
|
3451
3507
|
var HTTP_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
3452
3508
|
function tokenizeCurl(input) {
|
|
@@ -3748,10 +3804,12 @@ function parsePostmanCollection(input) {
|
|
|
3748
3804
|
items.forEach((item, idx) => {
|
|
3749
3805
|
const pathIds = parentPathIds ? [...parentPathIds, idx] : [idx];
|
|
3750
3806
|
if (Array.isArray(item.item)) {
|
|
3807
|
+
const folderAuth = item.auth ? parseAuth(item.auth, warnings, item.name) : void 0;
|
|
3751
3808
|
folders.push({
|
|
3752
3809
|
name: (item.name ?? "Untitled folder").trim() || "Untitled folder",
|
|
3753
3810
|
pathIds,
|
|
3754
|
-
parentPathIds
|
|
3811
|
+
parentPathIds,
|
|
3812
|
+
...folderAuth && folderAuth.type !== "none" ? { auth: folderAuth } : {}
|
|
3755
3813
|
});
|
|
3756
3814
|
walk(item.item, pathIds);
|
|
3757
3815
|
return;
|
|
@@ -3992,10 +4050,12 @@ function parseInsomniaCollection(input) {
|
|
|
3992
4050
|
const parentPath = r.parentId ? folderIndexById.get(r.parentId) ?? null : null;
|
|
3993
4051
|
const ourPath = parentPath ? [...parentPath, folderCounter++] : [folderCounter++];
|
|
3994
4052
|
folderIndexById.set(r._id ?? "", ourPath);
|
|
4053
|
+
const folderAuth = r.authentication ? parseAuth2(r.authentication, warnings, r.name) : void 0;
|
|
3995
4054
|
folders.push({
|
|
3996
4055
|
name: (r.name ?? "Untitled folder").trim() || "Untitled folder",
|
|
3997
4056
|
pathIds: ourPath,
|
|
3998
|
-
parentPathIds: parentPath
|
|
4057
|
+
parentPathIds: parentPath,
|
|
4058
|
+
...folderAuth && folderAuth.type !== "none" ? { auth: folderAuth } : {}
|
|
3999
4059
|
});
|
|
4000
4060
|
}
|
|
4001
4061
|
const requests = [];
|
|
@@ -4396,7 +4456,7 @@ function serializeFolderExport(envelope) {
|
|
|
4396
4456
|
return JSON.stringify(envelope, null, 2);
|
|
4397
4457
|
}
|
|
4398
4458
|
function suggestFolderExportFilename(envelope) {
|
|
4399
|
-
const slug = envelope.folder.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(
|
|
4459
|
+
const slug = envelope.folder.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-/, "").replace(/-$/, "");
|
|
4400
4460
|
const base = slug || "folder";
|
|
4401
4461
|
return `${base}.apicircle.json`;
|
|
4402
4462
|
}
|
|
@@ -5022,6 +5082,140 @@ function extractContext(result, extractions) {
|
|
|
5022
5082
|
return { extracted, warnings };
|
|
5023
5083
|
}
|
|
5024
5084
|
|
|
5085
|
+
// src/environment/resolveRequest.ts
|
|
5086
|
+
var import_shared2 = require("@apicircle/shared");
|
|
5087
|
+
function resolveRequestForExecution(args) {
|
|
5088
|
+
const refs = args.envPriorityOverride && args.envPriorityOverride.length > 0 ? args.envPriorityOverride : args.synced.environments.priorityOrder;
|
|
5089
|
+
const flatEnvs = {};
|
|
5090
|
+
for (const [name, vars] of Object.entries(args.localEnvs)) {
|
|
5091
|
+
flatEnvs[(0, import_shared2.envPriorityKey)({ kind: "local", name })] = vars;
|
|
5092
|
+
}
|
|
5093
|
+
for (const [linkId, byEnv] of Object.entries(args.linkedEnvs ?? {})) {
|
|
5094
|
+
for (const [envName, vars] of Object.entries(byEnv)) {
|
|
5095
|
+
flatEnvs[(0, import_shared2.envPriorityKey)({ kind: "linked", linkedWorkspaceId: linkId, envName })] = vars;
|
|
5096
|
+
}
|
|
5097
|
+
}
|
|
5098
|
+
const ctxMap = { ...args.globalContext ?? {} };
|
|
5099
|
+
for (const v of args.planVariables ?? []) {
|
|
5100
|
+
if (v.key) ctxMap[v.key] = v.value;
|
|
5101
|
+
}
|
|
5102
|
+
for (const v of args.request.contextVars) {
|
|
5103
|
+
if (v.key) ctxMap[v.key] = v.value;
|
|
5104
|
+
}
|
|
5105
|
+
const contextVars = Object.entries(ctxMap).map(([key, value]) => ({ key, value }));
|
|
5106
|
+
const scope = buildScope({
|
|
5107
|
+
contextVars,
|
|
5108
|
+
environments: flatEnvs,
|
|
5109
|
+
activeEnvName: null,
|
|
5110
|
+
// priorityOrder is the sole list the resolver consults.
|
|
5111
|
+
priorityOrder: refs.map(import_shared2.envPriorityKey),
|
|
5112
|
+
secrets: args.secrets ?? {}
|
|
5113
|
+
});
|
|
5114
|
+
const missing = /* @__PURE__ */ new Set();
|
|
5115
|
+
const interp = (s) => {
|
|
5116
|
+
const r = resolveString(s, scope);
|
|
5117
|
+
for (const m of r.missing) missing.add(m);
|
|
5118
|
+
return r.value;
|
|
5119
|
+
};
|
|
5120
|
+
const url = interp(args.request.url);
|
|
5121
|
+
const headers = args.request.headers.map((h) => ({
|
|
5122
|
+
...h,
|
|
5123
|
+
key: interp(h.key),
|
|
5124
|
+
value: interp(h.value)
|
|
5125
|
+
}));
|
|
5126
|
+
const query = args.request.query.map((q) => ({
|
|
5127
|
+
...q,
|
|
5128
|
+
key: interp(q.key),
|
|
5129
|
+
value: interp(q.value)
|
|
5130
|
+
}));
|
|
5131
|
+
let body = args.request.body;
|
|
5132
|
+
if (body.type === "json" || body.type === "text" || body.type === "xml" || body.type === "graphql" || body.type === "urlencoded") {
|
|
5133
|
+
body = { ...body, content: interp(body.content) };
|
|
5134
|
+
} else if (body.type === "form-data" && body.formRows) {
|
|
5135
|
+
body = {
|
|
5136
|
+
...body,
|
|
5137
|
+
formRows: body.formRows.map(
|
|
5138
|
+
(row) => row.kind === "text" ? { ...row, key: interp(row.key), value: interp(row.value) } : { ...row, key: interp(row.key) }
|
|
5139
|
+
)
|
|
5140
|
+
};
|
|
5141
|
+
}
|
|
5142
|
+
const inheritedAuth = resolveInheritedAuth({
|
|
5143
|
+
requestAuth: args.request.auth ?? { type: "none" },
|
|
5144
|
+
folderId: args.request.folderId,
|
|
5145
|
+
folders: args.synced.collections.folders
|
|
5146
|
+
});
|
|
5147
|
+
const auth = interpolateAuthVariables(inheritedAuth, interp);
|
|
5148
|
+
return {
|
|
5149
|
+
request: { ...args.request, url, headers, query, body, auth },
|
|
5150
|
+
scope,
|
|
5151
|
+
missing: [...missing]
|
|
5152
|
+
};
|
|
5153
|
+
}
|
|
5154
|
+
function interpolateAuthVariables(auth, interp) {
|
|
5155
|
+
const resolved = {};
|
|
5156
|
+
for (const [key, value] of Object.entries(auth)) {
|
|
5157
|
+
resolved[key] = key !== "type" && typeof value === "string" ? interp(value) : value;
|
|
5158
|
+
}
|
|
5159
|
+
return resolved;
|
|
5160
|
+
}
|
|
5161
|
+
function applyLinkedEnvironmentOverrides(source, linkedWorkspaceId, synced) {
|
|
5162
|
+
const overrides = Object.values(synced.linkedOverrides.environmentVars).filter(
|
|
5163
|
+
(o) => o.linkedWorkspaceId === linkedWorkspaceId
|
|
5164
|
+
);
|
|
5165
|
+
if (overrides.length === 0) return source;
|
|
5166
|
+
const items = {};
|
|
5167
|
+
for (const [envName, env] of Object.entries(source.items)) {
|
|
5168
|
+
const envOverrides = overrides.filter((o) => o.envName === envName);
|
|
5169
|
+
if (envOverrides.length === 0) {
|
|
5170
|
+
items[envName] = env;
|
|
5171
|
+
continue;
|
|
5172
|
+
}
|
|
5173
|
+
const removed = new Set(envOverrides.filter((o) => o.removed).map((o) => o.varKey));
|
|
5174
|
+
const replaceMap = new Map(envOverrides.filter((o) => !o.removed).map((o) => [o.varKey, o]));
|
|
5175
|
+
const variables = [];
|
|
5176
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
5177
|
+
for (const v of env.variables) {
|
|
5178
|
+
if (removed.has(v.key)) continue;
|
|
5179
|
+
const ov = replaceMap.get(v.key);
|
|
5180
|
+
if (ov) {
|
|
5181
|
+
variables.push({
|
|
5182
|
+
key: v.key,
|
|
5183
|
+
value: ov.value ?? v.value,
|
|
5184
|
+
encrypted: ov.encrypted ?? v.encrypted,
|
|
5185
|
+
...ov.secretKeyId !== void 0 ? { secretKeyId: ov.secretKeyId } : v.secretKeyId !== void 0 ? { secretKeyId: v.secretKeyId } : {}
|
|
5186
|
+
});
|
|
5187
|
+
} else {
|
|
5188
|
+
variables.push(v);
|
|
5189
|
+
}
|
|
5190
|
+
seenKeys.add(v.key);
|
|
5191
|
+
}
|
|
5192
|
+
for (const ov of envOverrides) {
|
|
5193
|
+
if (ov.removed) continue;
|
|
5194
|
+
if (seenKeys.has(ov.varKey)) continue;
|
|
5195
|
+
variables.push({
|
|
5196
|
+
key: ov.varKey,
|
|
5197
|
+
value: ov.value ?? "",
|
|
5198
|
+
encrypted: ov.encrypted ?? false,
|
|
5199
|
+
...ov.secretKeyId !== void 0 ? { secretKeyId: ov.secretKeyId } : {}
|
|
5200
|
+
});
|
|
5201
|
+
}
|
|
5202
|
+
items[envName] = { ...env, variables };
|
|
5203
|
+
}
|
|
5204
|
+
return { ...source, items };
|
|
5205
|
+
}
|
|
5206
|
+
function plaintextEnvMap(source) {
|
|
5207
|
+
const out = {};
|
|
5208
|
+
for (const [name, env] of Object.entries(source.items)) {
|
|
5209
|
+
const vars = {};
|
|
5210
|
+
for (const v of env.variables) {
|
|
5211
|
+
if (v.encrypted) continue;
|
|
5212
|
+
vars[v.key] = v.value;
|
|
5213
|
+
}
|
|
5214
|
+
out[name] = vars;
|
|
5215
|
+
}
|
|
5216
|
+
return out;
|
|
5217
|
+
}
|
|
5218
|
+
|
|
5025
5219
|
// src/secrets/crypto.ts
|
|
5026
5220
|
var IV_BYTES = 12;
|
|
5027
5221
|
var SALT_BYTES = 16;
|
|
@@ -5106,6 +5300,95 @@ function base64ToBytes(b64) {
|
|
|
5106
5300
|
return out;
|
|
5107
5301
|
}
|
|
5108
5302
|
|
|
5303
|
+
// src/secrets/passphraseKey.ts
|
|
5304
|
+
var PBKDF2_HASH = "SHA-256";
|
|
5305
|
+
var PBKDF2_ITERATIONS2 = 12e5;
|
|
5306
|
+
var SALT_BYTES2 = 16;
|
|
5307
|
+
var VERIFIER_SENTINEL = "apicircle/passphrase-verifier/v1";
|
|
5308
|
+
function base64Encode2(bytes) {
|
|
5309
|
+
let binary = "";
|
|
5310
|
+
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
5311
|
+
return btoa(binary);
|
|
5312
|
+
}
|
|
5313
|
+
function base64Decode2(b64) {
|
|
5314
|
+
const binary = atob(b64);
|
|
5315
|
+
const bytes = new Uint8Array(binary.length);
|
|
5316
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
5317
|
+
return bytes;
|
|
5318
|
+
}
|
|
5319
|
+
function utf8Bytes(s) {
|
|
5320
|
+
return new TextEncoder().encode(s);
|
|
5321
|
+
}
|
|
5322
|
+
async function deriveKey(passphrase, salt, iterations) {
|
|
5323
|
+
const baseKey = await crypto.subtle.importKey(
|
|
5324
|
+
"raw",
|
|
5325
|
+
utf8Bytes(passphrase),
|
|
5326
|
+
{ name: "PBKDF2" },
|
|
5327
|
+
false,
|
|
5328
|
+
["deriveKey"]
|
|
5329
|
+
);
|
|
5330
|
+
return crypto.subtle.deriveKey(
|
|
5331
|
+
{
|
|
5332
|
+
name: "PBKDF2",
|
|
5333
|
+
salt,
|
|
5334
|
+
iterations,
|
|
5335
|
+
hash: PBKDF2_HASH
|
|
5336
|
+
},
|
|
5337
|
+
baseKey,
|
|
5338
|
+
{ name: "AES-GCM", length: 256 },
|
|
5339
|
+
/* extractable */
|
|
5340
|
+
false,
|
|
5341
|
+
["encrypt", "decrypt"]
|
|
5342
|
+
);
|
|
5343
|
+
}
|
|
5344
|
+
async function computeVerifier(key) {
|
|
5345
|
+
const iv = new Uint8Array(12);
|
|
5346
|
+
const ct = await crypto.subtle.encrypt(
|
|
5347
|
+
{ name: "AES-GCM", iv },
|
|
5348
|
+
key,
|
|
5349
|
+
utf8Bytes(VERIFIER_SENTINEL)
|
|
5350
|
+
);
|
|
5351
|
+
return base64Encode2(new Uint8Array(ct));
|
|
5352
|
+
}
|
|
5353
|
+
async function initSecretCrypto(passphrase, iterations = PBKDF2_ITERATIONS2) {
|
|
5354
|
+
if (passphrase.length === 0) throw new Error("Passphrase cannot be empty");
|
|
5355
|
+
if (iterations < 1) throw new Error("iterations must be >= 1");
|
|
5356
|
+
const salt = crypto.getRandomValues(new Uint8Array(SALT_BYTES2));
|
|
5357
|
+
const key = await deriveKey(passphrase, salt, iterations);
|
|
5358
|
+
const verifier = await computeVerifier(key);
|
|
5359
|
+
return {
|
|
5360
|
+
crypto: {
|
|
5361
|
+
kdf: "pbkdf2-sha256-v1",
|
|
5362
|
+
salt: base64Encode2(salt),
|
|
5363
|
+
iterations,
|
|
5364
|
+
verifier
|
|
5365
|
+
},
|
|
5366
|
+
key
|
|
5367
|
+
};
|
|
5368
|
+
}
|
|
5369
|
+
async function unlockSecretCrypto(passphrase, blob) {
|
|
5370
|
+
if (blob.kdf !== "pbkdf2-sha256-v1") {
|
|
5371
|
+
return { ok: false, reason: `Unsupported KDF: ${String(blob.kdf)}` };
|
|
5372
|
+
}
|
|
5373
|
+
let salt;
|
|
5374
|
+
try {
|
|
5375
|
+
salt = base64Decode2(blob.salt);
|
|
5376
|
+
} catch {
|
|
5377
|
+
return { ok: false, reason: "Workspace secret salt is corrupt." };
|
|
5378
|
+
}
|
|
5379
|
+
let key;
|
|
5380
|
+
try {
|
|
5381
|
+
key = await deriveKey(passphrase, salt, blob.iterations);
|
|
5382
|
+
} catch (err) {
|
|
5383
|
+
return { ok: false, reason: err instanceof Error ? err.message : "Key derivation failed" };
|
|
5384
|
+
}
|
|
5385
|
+
const verifier = await computeVerifier(key);
|
|
5386
|
+
if (verifier !== blob.verifier) {
|
|
5387
|
+
return { ok: false, reason: "Wrong passphrase." };
|
|
5388
|
+
}
|
|
5389
|
+
return { ok: true, key };
|
|
5390
|
+
}
|
|
5391
|
+
|
|
5109
5392
|
// src/git/branchNames.ts
|
|
5110
5393
|
var SLUG_FALLBACK = "workspace";
|
|
5111
5394
|
var SUFFIX_LEN = 6;
|
|
@@ -5165,10 +5448,32 @@ function sortedReplacer(_key, value) {
|
|
|
5165
5448
|
|
|
5166
5449
|
// src/git/repoPaths.ts
|
|
5167
5450
|
var WORKSPACE_DIR = ".apicircle";
|
|
5168
|
-
var
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5451
|
+
var REGISTRY_JSON_PATH = `${WORKSPACE_DIR}/registry.json`;
|
|
5452
|
+
function workspaceJsonPath(workspaceId) {
|
|
5453
|
+
return `${WORKSPACE_DIR}/workspace-${workspaceId}/workspace.json`;
|
|
5454
|
+
}
|
|
5455
|
+
function attachmentsDir(workspaceId) {
|
|
5456
|
+
return `${WORKSPACE_DIR}/workspace-${workspaceId}/attachments`;
|
|
5457
|
+
}
|
|
5458
|
+
function attachmentPath(workspaceId, slotId) {
|
|
5459
|
+
return `${attachmentsDir(workspaceId)}/${slotId}`;
|
|
5460
|
+
}
|
|
5461
|
+
function parseRegistryActiveId(registryJsonContent) {
|
|
5462
|
+
try {
|
|
5463
|
+
const parsed = JSON.parse(registryJsonContent);
|
|
5464
|
+
return parsed.activeWorkspaceId ?? parsed.workspaces?.[0]?.id ?? null;
|
|
5465
|
+
} catch {
|
|
5466
|
+
return null;
|
|
5467
|
+
}
|
|
5468
|
+
}
|
|
5469
|
+
async function fetchRemoteWorkspaceJson(fetchFile) {
|
|
5470
|
+
const registryContent = await fetchFile(REGISTRY_JSON_PATH);
|
|
5471
|
+
if (registryContent === null) return { error: "No .apicircle/registry.json found in repo" };
|
|
5472
|
+
const wsId = parseRegistryActiveId(registryContent);
|
|
5473
|
+
if (!wsId) return { error: "Registry is empty \u2014 no workspaces found" };
|
|
5474
|
+
const wsContent = await fetchFile(workspaceJsonPath(wsId));
|
|
5475
|
+
if (wsContent === null) return { error: `No workspace.json at .apicircle/workspace-${wsId}/` };
|
|
5476
|
+
return { workspaceId: wsId, content: wsContent };
|
|
5172
5477
|
}
|
|
5173
5478
|
|
|
5174
5479
|
// src/git/parseWorkspaceJson.ts
|
|
@@ -5427,18 +5732,14 @@ function sortVersionsDesc(versions) {
|
|
|
5427
5732
|
}
|
|
5428
5733
|
|
|
5429
5734
|
// src/release/publishRelease.ts
|
|
5430
|
-
async function
|
|
5735
|
+
async function buildReleaseEntry(synced, args) {
|
|
5431
5736
|
const version = args.version.trim();
|
|
5432
5737
|
if (!isValidSemver(version)) {
|
|
5433
5738
|
throw new Error(`Invalid semver: ${args.version}`);
|
|
5434
5739
|
}
|
|
5435
|
-
const ledger = synced.releases.self ?? emptyLedger();
|
|
5436
|
-
if (ledger.versions.some((v) => v.version === version)) {
|
|
5437
|
-
throw new Error(`Version ${version} already exists in this workspace's release ledger`);
|
|
5438
|
-
}
|
|
5439
5740
|
const snapshotSource = serializeWorkspaceForGit(synced);
|
|
5440
5741
|
const workspaceSnapshot = await sha256Hex2(snapshotSource);
|
|
5441
|
-
|
|
5742
|
+
return {
|
|
5442
5743
|
version,
|
|
5443
5744
|
publishedAt: args.publishedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
5444
5745
|
notes: args.notes,
|
|
@@ -5448,23 +5749,36 @@ async function publishRelease(synced, args) {
|
|
|
5448
5749
|
...args.sha ? { sha: args.sha } : {},
|
|
5449
5750
|
...args.tagName ? { tagName: args.tagName } : {}
|
|
5450
5751
|
};
|
|
5752
|
+
}
|
|
5753
|
+
function appendReleaseEntry(synced, entry, now = entry.publishedAt) {
|
|
5754
|
+
if (!isValidSemver(entry.version)) {
|
|
5755
|
+
throw new Error(`Invalid semver: ${entry.version}`);
|
|
5756
|
+
}
|
|
5757
|
+
const ledger = synced.releases.self ?? emptyLedger();
|
|
5758
|
+
if (ledger.versions.some((v) => v.version === entry.version)) {
|
|
5759
|
+
throw new Error(`Version ${entry.version} already exists in this workspace's release ledger`);
|
|
5760
|
+
}
|
|
5451
5761
|
const next = {
|
|
5452
5762
|
versions: [...ledger.versions, entry],
|
|
5453
|
-
currentVersion: version
|
|
5763
|
+
currentVersion: entry.version
|
|
5454
5764
|
};
|
|
5455
5765
|
return {
|
|
5456
5766
|
...synced,
|
|
5457
5767
|
releases: { ...synced.releases, self: next },
|
|
5458
|
-
meta: { ...synced.meta, updatedAt:
|
|
5768
|
+
meta: { ...synced.meta, updatedAt: now }
|
|
5459
5769
|
};
|
|
5460
5770
|
}
|
|
5461
|
-
function
|
|
5462
|
-
|
|
5771
|
+
async function publishRelease(synced, args) {
|
|
5772
|
+
const entry = await buildReleaseEntry(synced, args);
|
|
5773
|
+
return appendReleaseEntry(synced, entry);
|
|
5774
|
+
}
|
|
5775
|
+
function deprecateRelease(synced, version, now = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
5776
|
+
return mapReleaseVersion(synced, version, (v) => ({ ...v, deprecated: true }), now);
|
|
5463
5777
|
}
|
|
5464
|
-
function yankRelease(synced, version) {
|
|
5465
|
-
return mapReleaseVersion(synced, version, (v) => ({ ...v, yanked: true }));
|
|
5778
|
+
function yankRelease(synced, version, now = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
5779
|
+
return mapReleaseVersion(synced, version, (v) => ({ ...v, yanked: true }), now);
|
|
5466
5780
|
}
|
|
5467
|
-
function mapReleaseVersion(synced, version, fn) {
|
|
5781
|
+
function mapReleaseVersion(synced, version, fn, now) {
|
|
5468
5782
|
const ledger = synced.releases.self;
|
|
5469
5783
|
if (!ledger) throw new Error("No releases to modify");
|
|
5470
5784
|
const idx = ledger.versions.findIndex((v) => v.version === version);
|
|
@@ -5474,7 +5788,7 @@ function mapReleaseVersion(synced, version, fn) {
|
|
|
5474
5788
|
return {
|
|
5475
5789
|
...synced,
|
|
5476
5790
|
releases: { ...synced.releases, self: { ...ledger, versions } },
|
|
5477
|
-
meta: { ...synced.meta, updatedAt:
|
|
5791
|
+
meta: { ...synced.meta, updatedAt: now }
|
|
5478
5792
|
};
|
|
5479
5793
|
}
|
|
5480
5794
|
function emptyLedger() {
|
|
@@ -5486,6 +5800,99 @@ async function sha256Hex2(text) {
|
|
|
5486
5800
|
return [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
5487
5801
|
}
|
|
5488
5802
|
|
|
5803
|
+
// src/linked/linkedSnapshot.ts
|
|
5804
|
+
var LINKED_FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
5805
|
+
var MAX_LINKED_JSON_BYTES = 16 * 1024 * 1024;
|
|
5806
|
+
function parseLinkedWorkspaceJson(text) {
|
|
5807
|
+
if (text.length > MAX_LINKED_JSON_BYTES) {
|
|
5808
|
+
throw new Error("Remote workspace.json exceeds 16 MiB");
|
|
5809
|
+
}
|
|
5810
|
+
let raw;
|
|
5811
|
+
try {
|
|
5812
|
+
raw = JSON.parse(
|
|
5813
|
+
text,
|
|
5814
|
+
(key, value) => LINKED_FORBIDDEN_KEYS.has(key) ? void 0 : value
|
|
5815
|
+
);
|
|
5816
|
+
} catch {
|
|
5817
|
+
throw new Error("Remote workspace.json is not valid JSON");
|
|
5818
|
+
}
|
|
5819
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
5820
|
+
throw new Error("Remote workspace.json is not an object");
|
|
5821
|
+
}
|
|
5822
|
+
const obj = raw;
|
|
5823
|
+
const asObject = (v) => typeof v === "object" && v !== null ? v : void 0;
|
|
5824
|
+
return {
|
|
5825
|
+
workspaceId: typeof obj.workspaceId === "string" ? obj.workspaceId : void 0,
|
|
5826
|
+
releases: asObject(obj.releases),
|
|
5827
|
+
collections: asObject(obj.collections),
|
|
5828
|
+
environments: asObject(obj.environments),
|
|
5829
|
+
secretKeys: asObject(obj.secretKeys),
|
|
5830
|
+
globalAssets: asObject(obj.globalAssets)
|
|
5831
|
+
};
|
|
5832
|
+
}
|
|
5833
|
+
function ledgerFromProbe(parsed) {
|
|
5834
|
+
return parsed.releases?.self ?? { versions: [], currentVersion: null };
|
|
5835
|
+
}
|
|
5836
|
+
function buildLinkedSnapshot(parsed, link) {
|
|
5837
|
+
if (!parsed.collections && !parsed.environments) return null;
|
|
5838
|
+
return {
|
|
5839
|
+
pulledAt: link.linkedAt,
|
|
5840
|
+
ref: link.pinnedVersion ? `v${link.pinnedVersion}` : `HEAD@${link.source.branch}`,
|
|
5841
|
+
collections: parsed.collections ?? {
|
|
5842
|
+
tree: { id: "remote-root", type: "root", children: [] },
|
|
5843
|
+
requests: {},
|
|
5844
|
+
folders: {}
|
|
5845
|
+
},
|
|
5846
|
+
environments: parsed.environments ?? {
|
|
5847
|
+
items: {},
|
|
5848
|
+
activeName: null,
|
|
5849
|
+
priorityOrder: []
|
|
5850
|
+
},
|
|
5851
|
+
...parsed.secretKeys ? { secretKeys: parsed.secretKeys } : {},
|
|
5852
|
+
...parsed.globalAssets ? { globalAssets: parsed.globalAssets } : {}
|
|
5853
|
+
};
|
|
5854
|
+
}
|
|
5855
|
+
|
|
5856
|
+
// src/linked/requestOverride.ts
|
|
5857
|
+
var OVERRIDABLE_FIELDS = [
|
|
5858
|
+
"name",
|
|
5859
|
+
"method",
|
|
5860
|
+
"url",
|
|
5861
|
+
"headers",
|
|
5862
|
+
"query",
|
|
5863
|
+
"pathParams",
|
|
5864
|
+
"cookies",
|
|
5865
|
+
"body",
|
|
5866
|
+
"auth",
|
|
5867
|
+
"contextVars",
|
|
5868
|
+
"extractions",
|
|
5869
|
+
"assertions"
|
|
5870
|
+
];
|
|
5871
|
+
function mergeRequestOverride(base, patch) {
|
|
5872
|
+
const merged = { ...base };
|
|
5873
|
+
const p = patch;
|
|
5874
|
+
const target = merged;
|
|
5875
|
+
for (const field of OVERRIDABLE_FIELDS) {
|
|
5876
|
+
if (p[field] !== void 0) target[field] = p[field];
|
|
5877
|
+
}
|
|
5878
|
+
return merged;
|
|
5879
|
+
}
|
|
5880
|
+
function computeRequestOverridePatch(base, effective) {
|
|
5881
|
+
const baseRec = { ...base };
|
|
5882
|
+
const effRec = { ...effective };
|
|
5883
|
+
const patch = {};
|
|
5884
|
+
const patchRec = patch;
|
|
5885
|
+
for (const field of OVERRIDABLE_FIELDS) {
|
|
5886
|
+
if (JSON.stringify(baseRec[field]) !== JSON.stringify(effRec[field])) {
|
|
5887
|
+
patchRec[field] = effRec[field];
|
|
5888
|
+
}
|
|
5889
|
+
}
|
|
5890
|
+
return patch;
|
|
5891
|
+
}
|
|
5892
|
+
function isEmptyOverridePatch(patch) {
|
|
5893
|
+
return Object.keys(patch).filter((k) => OVERRIDABLE_FIELDS.includes(k)).length === 0;
|
|
5894
|
+
}
|
|
5895
|
+
|
|
5489
5896
|
// src/editors/contentTypeLanguageMap.ts
|
|
5490
5897
|
var CONTENT_TYPE_LANGUAGE_MAP = {
|
|
5491
5898
|
"application/json": "json",
|
|
@@ -6418,7 +6825,8 @@ function previewLinkedUpdate(args) {
|
|
|
6418
6825
|
status,
|
|
6419
6826
|
base,
|
|
6420
6827
|
target,
|
|
6421
|
-
override
|
|
6828
|
+
override,
|
|
6829
|
+
...status === "both-changed" && base && target && override ? { autoMergeable: requestOverrideIsDisjoint(base, target, override) } : {}
|
|
6422
6830
|
});
|
|
6423
6831
|
}
|
|
6424
6832
|
const baseFolders = args.base?.collections.folders ?? {};
|
|
@@ -6498,6 +6906,34 @@ function classifyRequest(base, target, override) {
|
|
|
6498
6906
|
if (sourceChanged && !hasOverride) return "source-only";
|
|
6499
6907
|
return "both-changed";
|
|
6500
6908
|
}
|
|
6909
|
+
var OVERRIDABLE_REQUEST_FIELDS = [
|
|
6910
|
+
"name",
|
|
6911
|
+
"method",
|
|
6912
|
+
"url",
|
|
6913
|
+
"headers",
|
|
6914
|
+
"query",
|
|
6915
|
+
"pathParams",
|
|
6916
|
+
"cookies",
|
|
6917
|
+
"body",
|
|
6918
|
+
"auth",
|
|
6919
|
+
"contextVars",
|
|
6920
|
+
"extractions",
|
|
6921
|
+
"assertions"
|
|
6922
|
+
];
|
|
6923
|
+
function requestOverrideIsDisjoint(base, target, override) {
|
|
6924
|
+
const baseRec = { ...base };
|
|
6925
|
+
const targetRec = { ...target };
|
|
6926
|
+
const overriddenFields = Object.keys(override.patch);
|
|
6927
|
+
for (const f of overriddenFields) {
|
|
6928
|
+
if (!OVERRIDABLE_REQUEST_FIELDS.includes(f)) {
|
|
6929
|
+
continue;
|
|
6930
|
+
}
|
|
6931
|
+
if (!structurallyEqual2(baseRec[f], targetRec[f])) {
|
|
6932
|
+
return false;
|
|
6933
|
+
}
|
|
6934
|
+
}
|
|
6935
|
+
return true;
|
|
6936
|
+
}
|
|
6501
6937
|
function classifyFolder(base, target) {
|
|
6502
6938
|
if (!base && target) return "new-in-source";
|
|
6503
6939
|
if (base && !target) return "removed-in-source";
|
|
@@ -6547,7 +6983,7 @@ function applyLinkedUpdate(args) {
|
|
|
6547
6983
|
continue;
|
|
6548
6984
|
}
|
|
6549
6985
|
if (entry.status === "both-changed") {
|
|
6550
|
-
const choice = args.resolutions[id];
|
|
6986
|
+
const choice = args.resolutions[id] ?? (entry.autoMergeable ? "mine" : void 0);
|
|
6551
6987
|
if (!choice) {
|
|
6552
6988
|
throw new Error(
|
|
6553
6989
|
`applyLinkedUpdate: unresolved both-changed entry "${entry.label}" (${id})`
|
|
@@ -6558,7 +6994,8 @@ function applyLinkedUpdate(args) {
|
|
|
6558
6994
|
else if (entry.bucket === "environment-var") envVarOverridesByKey.delete(entry.key);
|
|
6559
6995
|
log.push({ entryKey: id, bucket: entry.bucket, action: "accept-source" });
|
|
6560
6996
|
} else {
|
|
6561
|
-
|
|
6997
|
+
const auto = entry.autoMergeable === true && !args.resolutions[id];
|
|
6998
|
+
log.push({ entryKey: id, bucket: entry.bucket, action: auto ? "auto-merge" : "keep-mine" });
|
|
6562
6999
|
}
|
|
6563
7000
|
}
|
|
6564
7001
|
}
|
|
@@ -6574,7 +7011,7 @@ function structurallyEqual2(a, b) {
|
|
|
6574
7011
|
}
|
|
6575
7012
|
|
|
6576
7013
|
// src/workspace/applyMutation.ts
|
|
6577
|
-
var
|
|
7014
|
+
var import_shared3 = require("@apicircle/shared");
|
|
6578
7015
|
|
|
6579
7016
|
// src/workspace/apicircleFolderImport.ts
|
|
6580
7017
|
function importApicircleFolderInto(synced, parsed, parentFolderId) {
|
|
@@ -6815,6 +7252,8 @@ function applyMutation(state, patch, options = {}) {
|
|
|
6815
7252
|
return applyFolderDelete(state, patch.id, now);
|
|
6816
7253
|
case "folder.move":
|
|
6817
7254
|
return applyFolderMove(state, patch.id, patch.newParentId, now);
|
|
7255
|
+
case "folder.update":
|
|
7256
|
+
return applyFolderUpdate(state, patch.id, patch.patch, now);
|
|
6818
7257
|
case "folder.import_apicircle":
|
|
6819
7258
|
return applyFolderImportApicircle(state, patch.parsed, patch.parentFolderId, now);
|
|
6820
7259
|
case "environment.upsert":
|
|
@@ -6827,6 +7266,10 @@ function applyMutation(state, patch, options = {}) {
|
|
|
6827
7266
|
return applyEnvSetPriority(state, patch.order, now);
|
|
6828
7267
|
case "secretKey.upsert":
|
|
6829
7268
|
return applySecretKeyUpsert(state, patch.meta, now);
|
|
7269
|
+
case "secret.crypto.set":
|
|
7270
|
+
return applySecretCryptoSet(state, patch.crypto, now);
|
|
7271
|
+
case "secret.crypto.clear":
|
|
7272
|
+
return applySecretCryptoClear(state, now);
|
|
6830
7273
|
case "assertion.upsert":
|
|
6831
7274
|
return applyAssertionUpsert(state, patch.requestId, patch.assertion, now);
|
|
6832
7275
|
case "assertion.delete":
|
|
@@ -6835,6 +7278,34 @@ function applyMutation(state, patch, options = {}) {
|
|
|
6835
7278
|
return applyMockUpsert(state, patch.mock, now);
|
|
6836
7279
|
case "mock.delete":
|
|
6837
7280
|
return applyMockDelete(state, patch.id, now);
|
|
7281
|
+
case "release.publish":
|
|
7282
|
+
return applyReleasePublish(state, patch.entry, now);
|
|
7283
|
+
case "release.deprecate":
|
|
7284
|
+
return applyReleaseDeprecate(state, patch.version, now);
|
|
7285
|
+
case "release.yank":
|
|
7286
|
+
return applyReleaseYank(state, patch.version, now);
|
|
7287
|
+
case "linkedWorkspace.upsert":
|
|
7288
|
+
return applyLinkedWorkspaceUpsert(state, patch.link, patch.ledger, patch.snapshot, now);
|
|
7289
|
+
case "linkedWorkspace.remove":
|
|
7290
|
+
return applyLinkedWorkspaceRemove(state, patch.id, now);
|
|
7291
|
+
case "linkedWorkspace.applyUpdate":
|
|
7292
|
+
return applyLinkedWorkspaceApplyUpdate(state, patch, now);
|
|
7293
|
+
case "linkedOverride.setRequest":
|
|
7294
|
+
return applyLinkedOverrideSetRequest(state, patch.override, now);
|
|
7295
|
+
case "linkedOverride.removeRequest":
|
|
7296
|
+
return applyLinkedOverrideRemoveRequest(state, patch.linkedWorkspaceId, patch.itemId, now);
|
|
7297
|
+
case "linkedOverride.setEnvVar":
|
|
7298
|
+
return applyLinkedOverrideSetEnvVar(state, patch.override, now);
|
|
7299
|
+
case "linkedOverride.removeEnvVar":
|
|
7300
|
+
return applyLinkedOverrideRemoveEnvVar(
|
|
7301
|
+
state,
|
|
7302
|
+
patch.linkedWorkspaceId,
|
|
7303
|
+
patch.envName,
|
|
7304
|
+
patch.varKey,
|
|
7305
|
+
now
|
|
7306
|
+
);
|
|
7307
|
+
case "linkedOverride.clearForLink":
|
|
7308
|
+
return applyLinkedOverrideClearForLink(state, patch.linkedWorkspaceId, now);
|
|
6838
7309
|
case "globalAsset.upsertFile":
|
|
6839
7310
|
return applyGlobalAssetUpsertFile(state, patch.file, now);
|
|
6840
7311
|
case "globalAsset.removeFile":
|
|
@@ -6871,12 +7342,13 @@ function applyRequestCreate(state, request, now) {
|
|
|
6871
7342
|
if (state.synced.collections.requests[request.id]) {
|
|
6872
7343
|
return { next: state, changedIds: [] };
|
|
6873
7344
|
}
|
|
7345
|
+
const tree = request.folderId ? state.synced.collections.tree : pushTreeChild(state.synced.collections.tree, { kind: "request", id: request.id });
|
|
6874
7346
|
const synced = {
|
|
6875
7347
|
...state.synced,
|
|
6876
7348
|
collections: {
|
|
6877
7349
|
...state.synced.collections,
|
|
6878
7350
|
requests: { ...state.synced.collections.requests, [request.id]: request },
|
|
6879
|
-
tree
|
|
7351
|
+
tree
|
|
6880
7352
|
},
|
|
6881
7353
|
meta: { ...state.synced.meta, updatedAt: now }
|
|
6882
7354
|
};
|
|
@@ -6925,12 +7397,13 @@ function applyFolderCreate(state, folder, now) {
|
|
|
6925
7397
|
if (state.synced.collections.folders[folder.id]) {
|
|
6926
7398
|
return { next: state, changedIds: [] };
|
|
6927
7399
|
}
|
|
7400
|
+
const tree = folder.parentId ? state.synced.collections.tree : pushTreeChild(state.synced.collections.tree, { kind: "folder", id: folder.id });
|
|
6928
7401
|
const synced = {
|
|
6929
7402
|
...state.synced,
|
|
6930
7403
|
collections: {
|
|
6931
7404
|
...state.synced.collections,
|
|
6932
7405
|
folders: { ...state.synced.collections.folders, [folder.id]: folder },
|
|
6933
|
-
tree
|
|
7406
|
+
tree
|
|
6934
7407
|
},
|
|
6935
7408
|
meta: { ...state.synced.meta, updatedAt: now }
|
|
6936
7409
|
};
|
|
@@ -6999,6 +7472,57 @@ function applyFolderMove(state, id, newParentId, now) {
|
|
|
6999
7472
|
};
|
|
7000
7473
|
return { next: { ...state, synced }, changedIds: [id] };
|
|
7001
7474
|
}
|
|
7475
|
+
function applyFolderUpdate(state, id, patch, now) {
|
|
7476
|
+
const folder = state.synced.collections.folders[id];
|
|
7477
|
+
if (!folder) {
|
|
7478
|
+
return { next: state, changedIds: [] };
|
|
7479
|
+
}
|
|
7480
|
+
const nameChanging = "name" in patch && patch.name !== void 0;
|
|
7481
|
+
const authChanging = "auth" in patch;
|
|
7482
|
+
if (!nameChanging && !authChanging) {
|
|
7483
|
+
return { next: state, changedIds: [] };
|
|
7484
|
+
}
|
|
7485
|
+
let nextName = folder.name;
|
|
7486
|
+
if (nameChanging) {
|
|
7487
|
+
const trimmed = patch.name.trim();
|
|
7488
|
+
if (!trimmed) {
|
|
7489
|
+
} else if (trimmed === folder.name) {
|
|
7490
|
+
} else if (!isFolderNameUnique(state, folder.parentId, trimmed, id)) {
|
|
7491
|
+
return { next: state, changedIds: [] };
|
|
7492
|
+
} else {
|
|
7493
|
+
nextName = trimmed;
|
|
7494
|
+
}
|
|
7495
|
+
}
|
|
7496
|
+
const nextFolder = { ...folder, name: nextName };
|
|
7497
|
+
if (authChanging) {
|
|
7498
|
+
if (patch.auth === void 0) {
|
|
7499
|
+
delete nextFolder.auth;
|
|
7500
|
+
} else {
|
|
7501
|
+
nextFolder.auth = patch.auth;
|
|
7502
|
+
}
|
|
7503
|
+
}
|
|
7504
|
+
if (nextFolder.name === folder.name && nextFolder.auth === folder.auth) {
|
|
7505
|
+
return { next: state, changedIds: [] };
|
|
7506
|
+
}
|
|
7507
|
+
const synced = {
|
|
7508
|
+
...state.synced,
|
|
7509
|
+
collections: {
|
|
7510
|
+
...state.synced.collections,
|
|
7511
|
+
folders: { ...state.synced.collections.folders, [id]: nextFolder }
|
|
7512
|
+
},
|
|
7513
|
+
meta: { ...state.synced.meta, updatedAt: now }
|
|
7514
|
+
};
|
|
7515
|
+
return { next: { ...state, synced }, changedIds: [id] };
|
|
7516
|
+
}
|
|
7517
|
+
function isFolderNameUnique(state, parentId, trimmedCandidate, ignoreId) {
|
|
7518
|
+
const target = trimmedCandidate.toLowerCase();
|
|
7519
|
+
for (const f of Object.values(state.synced.collections.folders)) {
|
|
7520
|
+
if (f.id === ignoreId) continue;
|
|
7521
|
+
if (f.parentId !== parentId) continue;
|
|
7522
|
+
if (f.name.trim().toLowerCase() === target) return false;
|
|
7523
|
+
}
|
|
7524
|
+
return true;
|
|
7525
|
+
}
|
|
7002
7526
|
function applyFolderImportApicircle(state, parsed, parentFolderId, now) {
|
|
7003
7527
|
const result = importApicircleFolderInto(
|
|
7004
7528
|
state.synced,
|
|
@@ -7078,7 +7602,7 @@ function applyEnvSetPriority(state, order, now) {
|
|
|
7078
7602
|
const knownLocal = new Set(Object.keys(state.synced.environments.items));
|
|
7079
7603
|
const seen = /* @__PURE__ */ new Set();
|
|
7080
7604
|
const filtered = order.filter((ref) => {
|
|
7081
|
-
const key = (0,
|
|
7605
|
+
const key = (0, import_shared3.envPriorityKey)(ref);
|
|
7082
7606
|
if (seen.has(key)) return false;
|
|
7083
7607
|
if (ref.kind === "local" && !knownLocal.has(ref.name)) return false;
|
|
7084
7608
|
seen.add(key);
|
|
@@ -7089,7 +7613,7 @@ function applyEnvSetPriority(state, order, now) {
|
|
|
7089
7613
|
environments: { ...state.synced.environments, priorityOrder: filtered },
|
|
7090
7614
|
meta: { ...state.synced.meta, updatedAt: now }
|
|
7091
7615
|
};
|
|
7092
|
-
return { next: { ...state, synced }, changedIds: filtered.map(
|
|
7616
|
+
return { next: { ...state, synced }, changedIds: filtered.map(import_shared3.envPriorityKey) };
|
|
7093
7617
|
}
|
|
7094
7618
|
function applySecretKeyUpsert(state, meta, now) {
|
|
7095
7619
|
if (!meta.id || !meta.label.trim() || !meta.salt) {
|
|
@@ -7105,6 +7629,28 @@ function applySecretKeyUpsert(state, meta, now) {
|
|
|
7105
7629
|
};
|
|
7106
7630
|
return { next: { ...state, synced }, changedIds: [meta.id] };
|
|
7107
7631
|
}
|
|
7632
|
+
function applySecretCryptoSet(state, crypto2, now) {
|
|
7633
|
+
if (!crypto2 || crypto2.kdf !== "pbkdf2-sha256-v1" || !crypto2.salt || !crypto2.verifier || !(crypto2.iterations >= 1)) {
|
|
7634
|
+
return { next: state, changedIds: [] };
|
|
7635
|
+
}
|
|
7636
|
+
const synced = {
|
|
7637
|
+
...state.synced,
|
|
7638
|
+
secretCrypto: { ...crypto2 },
|
|
7639
|
+
meta: { ...state.synced.meta, updatedAt: now }
|
|
7640
|
+
};
|
|
7641
|
+
return { next: { ...state, synced }, changedIds: ["secret.crypto"] };
|
|
7642
|
+
}
|
|
7643
|
+
function applySecretCryptoClear(state, now) {
|
|
7644
|
+
if (!state.synced.secretCrypto) {
|
|
7645
|
+
return { next: state, changedIds: [] };
|
|
7646
|
+
}
|
|
7647
|
+
const synced = {
|
|
7648
|
+
...state.synced,
|
|
7649
|
+
secretCrypto: null,
|
|
7650
|
+
meta: { ...state.synced.meta, updatedAt: now }
|
|
7651
|
+
};
|
|
7652
|
+
return { next: { ...state, synced }, changedIds: ["secret.crypto"] };
|
|
7653
|
+
}
|
|
7108
7654
|
function applyAssertionUpsert(state, requestId, assertion, now) {
|
|
7109
7655
|
const request = state.synced.collections.requests[requestId];
|
|
7110
7656
|
if (!request) {
|
|
@@ -7162,6 +7708,191 @@ function applyMockDelete(state, id, now) {
|
|
|
7162
7708
|
} : state.local;
|
|
7163
7709
|
return { next: { synced, local }, changedIds: [id] };
|
|
7164
7710
|
}
|
|
7711
|
+
function applyReleasePublish(state, entry, now) {
|
|
7712
|
+
const synced = appendReleaseEntry(state.synced, entry, now);
|
|
7713
|
+
return { next: { ...state, synced }, changedIds: [entry.version] };
|
|
7714
|
+
}
|
|
7715
|
+
function applyReleaseDeprecate(state, version, now) {
|
|
7716
|
+
const synced = deprecateRelease(state.synced, version, now);
|
|
7717
|
+
return { next: { ...state, synced }, changedIds: [version] };
|
|
7718
|
+
}
|
|
7719
|
+
function applyReleaseYank(state, version, now) {
|
|
7720
|
+
const synced = yankRelease(state.synced, version, now);
|
|
7721
|
+
return { next: { ...state, synced }, changedIds: [version] };
|
|
7722
|
+
}
|
|
7723
|
+
function applyLinkedWorkspaceUpsert(state, link, ledger, snapshot2, now) {
|
|
7724
|
+
const synced = {
|
|
7725
|
+
...state.synced,
|
|
7726
|
+
linkedWorkspaces: { ...state.synced.linkedWorkspaces, [link.id]: link },
|
|
7727
|
+
releases: ledger ? {
|
|
7728
|
+
...state.synced.releases,
|
|
7729
|
+
perLink: { ...state.synced.releases.perLink, [link.id]: ledger }
|
|
7730
|
+
} : state.synced.releases,
|
|
7731
|
+
meta: { ...state.synced.meta, updatedAt: now }
|
|
7732
|
+
};
|
|
7733
|
+
const local = snapshot2 ? {
|
|
7734
|
+
...state.local,
|
|
7735
|
+
linkedCollections: { ...state.local.linkedCollections, [link.id]: snapshot2 }
|
|
7736
|
+
} : state.local;
|
|
7737
|
+
return { next: { synced, local }, changedIds: [link.id] };
|
|
7738
|
+
}
|
|
7739
|
+
function applyLinkedWorkspaceRemove(state, id, now) {
|
|
7740
|
+
if (!state.synced.linkedWorkspaces[id]) {
|
|
7741
|
+
return { next: state, changedIds: [] };
|
|
7742
|
+
}
|
|
7743
|
+
const linkedWorkspaces = { ...state.synced.linkedWorkspaces };
|
|
7744
|
+
delete linkedWorkspaces[id];
|
|
7745
|
+
const perLink = { ...state.synced.releases.perLink };
|
|
7746
|
+
delete perLink[id];
|
|
7747
|
+
const prefix = `${id}:`;
|
|
7748
|
+
const dropPrefixed = (map) => Object.fromEntries(Object.entries(map).filter(([k]) => !k.startsWith(prefix)));
|
|
7749
|
+
const synced = {
|
|
7750
|
+
...state.synced,
|
|
7751
|
+
linkedWorkspaces,
|
|
7752
|
+
releases: { ...state.synced.releases, perLink },
|
|
7753
|
+
linkedOverrides: {
|
|
7754
|
+
requests: dropPrefixed(state.synced.linkedOverrides.requests),
|
|
7755
|
+
environmentVars: dropPrefixed(state.synced.linkedOverrides.environmentVars)
|
|
7756
|
+
},
|
|
7757
|
+
meta: { ...state.synced.meta, updatedAt: now }
|
|
7758
|
+
};
|
|
7759
|
+
const linkedCollections = { ...state.local.linkedCollections };
|
|
7760
|
+
delete linkedCollections[id];
|
|
7761
|
+
const githubLinks = { ...state.local.sessions.github.links };
|
|
7762
|
+
delete githubLinks[id];
|
|
7763
|
+
const local = {
|
|
7764
|
+
...state.local,
|
|
7765
|
+
linkedCollections,
|
|
7766
|
+
sessions: {
|
|
7767
|
+
...state.local.sessions,
|
|
7768
|
+
github: { ...state.local.sessions.github, links: githubLinks }
|
|
7769
|
+
}
|
|
7770
|
+
};
|
|
7771
|
+
return { next: { synced, local }, changedIds: [id] };
|
|
7772
|
+
}
|
|
7773
|
+
function applyLinkedWorkspaceApplyUpdate(state, patch, now) {
|
|
7774
|
+
const link = state.synced.linkedWorkspaces[patch.id];
|
|
7775
|
+
if (!link) {
|
|
7776
|
+
return { next: state, changedIds: [] };
|
|
7777
|
+
}
|
|
7778
|
+
const prefix = `${patch.id}:`;
|
|
7779
|
+
const otherRequests = Object.fromEntries(
|
|
7780
|
+
Object.entries(state.synced.linkedOverrides.requests).filter(([k]) => !k.startsWith(prefix))
|
|
7781
|
+
);
|
|
7782
|
+
for (const o of patch.requestOverrides) {
|
|
7783
|
+
otherRequests[`${o.linkedWorkspaceId}:${o.itemId}`] = o;
|
|
7784
|
+
}
|
|
7785
|
+
const otherEnvVars = Object.fromEntries(
|
|
7786
|
+
Object.entries(state.synced.linkedOverrides.environmentVars).filter(
|
|
7787
|
+
([k]) => !k.startsWith(prefix)
|
|
7788
|
+
)
|
|
7789
|
+
);
|
|
7790
|
+
for (const o of patch.envVarOverrides) {
|
|
7791
|
+
otherEnvVars[`${o.linkedWorkspaceId}:${o.envName}:${o.varKey}`] = o;
|
|
7792
|
+
}
|
|
7793
|
+
const synced = {
|
|
7794
|
+
...state.synced,
|
|
7795
|
+
linkedWorkspaces: {
|
|
7796
|
+
...state.synced.linkedWorkspaces,
|
|
7797
|
+
[patch.id]: { ...link, pinnedVersion: patch.pinnedVersion }
|
|
7798
|
+
},
|
|
7799
|
+
releases: {
|
|
7800
|
+
...state.synced.releases,
|
|
7801
|
+
perLink: { ...state.synced.releases.perLink, [patch.id]: patch.ledger }
|
|
7802
|
+
},
|
|
7803
|
+
linkedOverrides: { requests: otherRequests, environmentVars: otherEnvVars },
|
|
7804
|
+
meta: { ...state.synced.meta, updatedAt: now }
|
|
7805
|
+
};
|
|
7806
|
+
const local = {
|
|
7807
|
+
...state.local,
|
|
7808
|
+
linkedCollections: { ...state.local.linkedCollections, [patch.id]: patch.snapshot }
|
|
7809
|
+
};
|
|
7810
|
+
return { next: { synced, local }, changedIds: [patch.id] };
|
|
7811
|
+
}
|
|
7812
|
+
function applyLinkedOverrideSetRequest(state, override, now) {
|
|
7813
|
+
const key = `${override.linkedWorkspaceId}:${override.itemId}`;
|
|
7814
|
+
const synced = {
|
|
7815
|
+
...state.synced,
|
|
7816
|
+
linkedOverrides: {
|
|
7817
|
+
...state.synced.linkedOverrides,
|
|
7818
|
+
requests: {
|
|
7819
|
+
...state.synced.linkedOverrides.requests,
|
|
7820
|
+
[key]: { ...override, updatedAt: now }
|
|
7821
|
+
}
|
|
7822
|
+
},
|
|
7823
|
+
meta: { ...state.synced.meta, updatedAt: now }
|
|
7824
|
+
};
|
|
7825
|
+
return { next: { ...state, synced }, changedIds: [key] };
|
|
7826
|
+
}
|
|
7827
|
+
function applyLinkedOverrideRemoveRequest(state, linkedWorkspaceId, itemId, now) {
|
|
7828
|
+
const key = `${linkedWorkspaceId}:${itemId}`;
|
|
7829
|
+
if (!state.synced.linkedOverrides.requests[key]) {
|
|
7830
|
+
return { next: state, changedIds: [] };
|
|
7831
|
+
}
|
|
7832
|
+
const requests = { ...state.synced.linkedOverrides.requests };
|
|
7833
|
+
delete requests[key];
|
|
7834
|
+
const synced = {
|
|
7835
|
+
...state.synced,
|
|
7836
|
+
linkedOverrides: { ...state.synced.linkedOverrides, requests },
|
|
7837
|
+
meta: { ...state.synced.meta, updatedAt: now }
|
|
7838
|
+
};
|
|
7839
|
+
return { next: { ...state, synced }, changedIds: [key] };
|
|
7840
|
+
}
|
|
7841
|
+
function applyLinkedOverrideSetEnvVar(state, override, now) {
|
|
7842
|
+
const key = `${override.linkedWorkspaceId}:${override.envName}:${override.varKey}`;
|
|
7843
|
+
const synced = {
|
|
7844
|
+
...state.synced,
|
|
7845
|
+
linkedOverrides: {
|
|
7846
|
+
...state.synced.linkedOverrides,
|
|
7847
|
+
environmentVars: {
|
|
7848
|
+
...state.synced.linkedOverrides.environmentVars,
|
|
7849
|
+
[key]: { ...override, updatedAt: now }
|
|
7850
|
+
}
|
|
7851
|
+
},
|
|
7852
|
+
meta: { ...state.synced.meta, updatedAt: now }
|
|
7853
|
+
};
|
|
7854
|
+
return { next: { ...state, synced }, changedIds: [key] };
|
|
7855
|
+
}
|
|
7856
|
+
function applyLinkedOverrideRemoveEnvVar(state, linkedWorkspaceId, envName, varKey, now) {
|
|
7857
|
+
const key = `${linkedWorkspaceId}:${envName}:${varKey}`;
|
|
7858
|
+
if (!state.synced.linkedOverrides.environmentVars[key]) {
|
|
7859
|
+
return { next: state, changedIds: [] };
|
|
7860
|
+
}
|
|
7861
|
+
const environmentVars = { ...state.synced.linkedOverrides.environmentVars };
|
|
7862
|
+
delete environmentVars[key];
|
|
7863
|
+
const synced = {
|
|
7864
|
+
...state.synced,
|
|
7865
|
+
linkedOverrides: { ...state.synced.linkedOverrides, environmentVars },
|
|
7866
|
+
meta: { ...state.synced.meta, updatedAt: now }
|
|
7867
|
+
};
|
|
7868
|
+
return { next: { ...state, synced }, changedIds: [key] };
|
|
7869
|
+
}
|
|
7870
|
+
function applyLinkedOverrideClearForLink(state, linkedWorkspaceId, now) {
|
|
7871
|
+
const prefix = `${linkedWorkspaceId}:`;
|
|
7872
|
+
const requestKeys = Object.keys(state.synced.linkedOverrides.requests).filter(
|
|
7873
|
+
(k) => k.startsWith(prefix)
|
|
7874
|
+
);
|
|
7875
|
+
const envKeys = Object.keys(state.synced.linkedOverrides.environmentVars).filter(
|
|
7876
|
+
(k) => k.startsWith(prefix)
|
|
7877
|
+
);
|
|
7878
|
+
if (requestKeys.length === 0 && envKeys.length === 0) {
|
|
7879
|
+
return { next: state, changedIds: [] };
|
|
7880
|
+
}
|
|
7881
|
+
const requests = Object.fromEntries(
|
|
7882
|
+
Object.entries(state.synced.linkedOverrides.requests).filter(([k]) => !k.startsWith(prefix))
|
|
7883
|
+
);
|
|
7884
|
+
const environmentVars = Object.fromEntries(
|
|
7885
|
+
Object.entries(state.synced.linkedOverrides.environmentVars).filter(
|
|
7886
|
+
([k]) => !k.startsWith(prefix)
|
|
7887
|
+
)
|
|
7888
|
+
);
|
|
7889
|
+
const synced = {
|
|
7890
|
+
...state.synced,
|
|
7891
|
+
linkedOverrides: { requests, environmentVars },
|
|
7892
|
+
meta: { ...state.synced.meta, updatedAt: now }
|
|
7893
|
+
};
|
|
7894
|
+
return { next: { ...state, synced }, changedIds: [...requestKeys, ...envKeys] };
|
|
7895
|
+
}
|
|
7165
7896
|
function applyGlobalAssetUpsertFile(state, file, now) {
|
|
7166
7897
|
const files = state.synced.globalAssets.files ?? {};
|
|
7167
7898
|
const existing = files[file.id];
|
|
@@ -7232,6 +7963,14 @@ function applyGlobalAssetRemoveFile(state, id, now) {
|
|
|
7232
7963
|
delete nextUsage[id];
|
|
7233
7964
|
local = { ...local, assetUsageIndex: nextUsage };
|
|
7234
7965
|
}
|
|
7966
|
+
const existing = files[id];
|
|
7967
|
+
const hadRemoteRef = Boolean(existing.workingBranchRef || existing.baseBranchRef);
|
|
7968
|
+
if (hadRemoteRef && !(local.pendingAttachmentDeletes ?? []).includes(existing.slotId)) {
|
|
7969
|
+
local = {
|
|
7970
|
+
...local,
|
|
7971
|
+
pendingAttachmentDeletes: [...local.pendingAttachmentDeletes ?? [], existing.slotId]
|
|
7972
|
+
};
|
|
7973
|
+
}
|
|
7235
7974
|
const synced = {
|
|
7236
7975
|
...state.synced,
|
|
7237
7976
|
collections: { ...state.synced.collections, requests },
|
|
@@ -7388,7 +8127,7 @@ function evictSnapshotsToCap(entries, maxBytes) {
|
|
|
7388
8127
|
};
|
|
7389
8128
|
}
|
|
7390
8129
|
function applySnapshotCapture(state, args, now) {
|
|
7391
|
-
const id = args.id ?? (0,
|
|
8130
|
+
const id = args.id ?? (0, import_shared3.generateId)();
|
|
7392
8131
|
const snapshot2 = {
|
|
7393
8132
|
id,
|
|
7394
8133
|
createdAt: now,
|
|
@@ -7477,7 +8216,7 @@ function applyHistoryPurge(state, olderThanMs) {
|
|
|
7477
8216
|
}
|
|
7478
8217
|
|
|
7479
8218
|
// src/workspace/runPlan.ts
|
|
7480
|
-
var
|
|
8219
|
+
var import_shared4 = require("@apicircle/shared");
|
|
7481
8220
|
var MAX_REQUEST_RUNS = 500;
|
|
7482
8221
|
var MAX_PLAN_RUNS = 200;
|
|
7483
8222
|
var ANONYMOUS_ACTOR = { kind: "unknown", name: "unknown" };
|
|
@@ -7543,22 +8282,6 @@ function lookupPlanStepRequest(step, synced, local) {
|
|
|
7543
8282
|
linkedGlobalAssets: snapshot2.globalAssets
|
|
7544
8283
|
};
|
|
7545
8284
|
}
|
|
7546
|
-
function mergeRequestOverride(base, patch) {
|
|
7547
|
-
const merged = { ...base };
|
|
7548
|
-
if (patch.name !== void 0) merged.name = patch.name;
|
|
7549
|
-
if (patch.method !== void 0) merged.method = patch.method;
|
|
7550
|
-
if (patch.url !== void 0) merged.url = patch.url;
|
|
7551
|
-
if (patch.headers !== void 0) merged.headers = patch.headers;
|
|
7552
|
-
if (patch.query !== void 0) merged.query = patch.query;
|
|
7553
|
-
if (patch.pathParams !== void 0) merged.pathParams = patch.pathParams;
|
|
7554
|
-
if (patch.cookies !== void 0) merged.cookies = patch.cookies;
|
|
7555
|
-
if (patch.body !== void 0) merged.body = patch.body;
|
|
7556
|
-
if (patch.auth !== void 0) merged.auth = patch.auth;
|
|
7557
|
-
if (patch.contextVars !== void 0) merged.contextVars = patch.contextVars;
|
|
7558
|
-
if (patch.extractions !== void 0) merged.extractions = patch.extractions;
|
|
7559
|
-
if (patch.assertions !== void 0) merged.assertions = patch.assertions;
|
|
7560
|
-
return merged;
|
|
7561
|
-
}
|
|
7562
8285
|
function applyEnvironmentOverrides(source, linkedWorkspaceId, synced) {
|
|
7563
8286
|
const overrides = Object.values(synced.linkedOverrides.environmentVars).filter(
|
|
7564
8287
|
(override) => override.linkedWorkspaceId === linkedWorkspaceId
|
|
@@ -7624,7 +8347,7 @@ async function runPlan(state, planId, opts = {}) {
|
|
|
7624
8347
|
const baseRefs = plan.envPriorityOrder.length > 0 ? plan.envPriorityOrder : state.synced.environments.priorityOrder;
|
|
7625
8348
|
const envRefs = opts.env ? [{ kind: "local", name: opts.env }, ...baseRefs] : baseRefs;
|
|
7626
8349
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7627
|
-
const planRunId = (0,
|
|
8350
|
+
const planRunId = (0, import_shared4.generateId)();
|
|
7628
8351
|
const t0 = Date.now();
|
|
7629
8352
|
const stepRecords = [];
|
|
7630
8353
|
const newRequestRuns = [];
|
|
@@ -7657,7 +8380,7 @@ async function runPlan(state, planId, opts = {}) {
|
|
|
7657
8380
|
const lookup2 = lookupPlanStepRequest(step, state.synced, state.local);
|
|
7658
8381
|
const baseRequest = lookup2.request;
|
|
7659
8382
|
if (!baseRequest) {
|
|
7660
|
-
const runId = (0,
|
|
8383
|
+
const runId = (0, import_shared4.generateId)();
|
|
7661
8384
|
const error = lookup2.error ?? "Request no longer exists in workspace.";
|
|
7662
8385
|
newRequestRuns.push(orphanRun(runId, step.requestId, error));
|
|
7663
8386
|
stepRecords.push({ requestRunId: runId, passed: false });
|
|
@@ -7775,7 +8498,7 @@ function buildEnvMaps(synced, secretsById, local) {
|
|
|
7775
8498
|
vars[v.key] = v.value;
|
|
7776
8499
|
}
|
|
7777
8500
|
}
|
|
7778
|
-
flat[(0,
|
|
8501
|
+
flat[(0, import_shared4.envPriorityKey)({ kind: "local", name })] = vars;
|
|
7779
8502
|
}
|
|
7780
8503
|
if (local) {
|
|
7781
8504
|
for (const [linkId, snapshot2] of Object.entries(local.linkedCollections)) {
|
|
@@ -7792,7 +8515,7 @@ function buildEnvMaps(synced, secretsById, local) {
|
|
|
7792
8515
|
vars[variable.key] = variable.value;
|
|
7793
8516
|
}
|
|
7794
8517
|
}
|
|
7795
|
-
flat[(0,
|
|
8518
|
+
flat[(0, import_shared4.envPriorityKey)({ kind: "linked", linkedWorkspaceId: linkId, envName })] = vars;
|
|
7796
8519
|
}
|
|
7797
8520
|
}
|
|
7798
8521
|
}
|
|
@@ -7819,7 +8542,7 @@ function resolveRequest(request, synced, plan, envRefs, globalContext, flatEnvs,
|
|
|
7819
8542
|
contextVars: Object.entries(ctxMap).map(([key, value]) => ({ key, value })),
|
|
7820
8543
|
environments: flatEnvs,
|
|
7821
8544
|
activeEnvName: null,
|
|
7822
|
-
priorityOrder: envRefs.map(
|
|
8545
|
+
priorityOrder: envRefs.map(import_shared4.envPriorityKey),
|
|
7823
8546
|
secrets: secretsByLabel
|
|
7824
8547
|
});
|
|
7825
8548
|
const missing = /* @__PURE__ */ new Set();
|
|
@@ -7889,7 +8612,7 @@ function orphanRun(id, requestId, error) {
|
|
|
7889
8612
|
function buildRequestRun(resolved, result, assertions) {
|
|
7890
8613
|
const { preview, truncated } = clampPreview(result.body ?? "");
|
|
7891
8614
|
return {
|
|
7892
|
-
id: (0,
|
|
8615
|
+
id: (0, import_shared4.generateId)(),
|
|
7893
8616
|
requestId: resolved.id,
|
|
7894
8617
|
startedAt: result.startedAt,
|
|
7895
8618
|
durationMs: result.durationMs,
|
|
@@ -7909,8 +8632,8 @@ function buildRequestRun(resolved, result, assertions) {
|
|
|
7909
8632
|
};
|
|
7910
8633
|
}
|
|
7911
8634
|
function clampPreview(value) {
|
|
7912
|
-
if (value.length <=
|
|
7913
|
-
return { preview: value.slice(0,
|
|
8635
|
+
if (value.length <= import_shared4.RUN_BODY_PREVIEW_LIMIT) return { preview: value, truncated: false };
|
|
8636
|
+
return { preview: value.slice(0, import_shared4.RUN_BODY_PREVIEW_LIMIT), truncated: true };
|
|
7914
8637
|
}
|
|
7915
8638
|
function redactUrlCredentials(url) {
|
|
7916
8639
|
try {
|
|
@@ -8133,9 +8856,9 @@ function toCsv(value) {
|
|
|
8133
8856
|
}
|
|
8134
8857
|
|
|
8135
8858
|
// src/transform/computeSavings.ts
|
|
8136
|
-
var
|
|
8859
|
+
var import_shared5 = require("@apicircle/shared");
|
|
8137
8860
|
function computeTransformSavings(body, contentType) {
|
|
8138
|
-
const originalBytes = (0,
|
|
8861
|
+
const originalBytes = (0, import_shared5.utf8ByteLength)(body);
|
|
8139
8862
|
if (!isJsonLike(body, contentType)) {
|
|
8140
8863
|
return { originalBytes, minifiedBytes: originalBytes, candidates: [] };
|
|
8141
8864
|
}
|
|
@@ -8146,7 +8869,7 @@ function computeTransformSavings(body, contentType) {
|
|
|
8146
8869
|
return { originalBytes, minifiedBytes: originalBytes, candidates: [] };
|
|
8147
8870
|
}
|
|
8148
8871
|
const minified = JSON.stringify(parsed);
|
|
8149
|
-
const minifiedBytes = (0,
|
|
8872
|
+
const minifiedBytes = (0, import_shared5.utf8ByteLength)(minified);
|
|
8150
8873
|
const candidates = [];
|
|
8151
8874
|
try {
|
|
8152
8875
|
const toon = toToon(parsed);
|
|
@@ -8173,7 +8896,7 @@ function computeTransformSavings(body, contentType) {
|
|
|
8173
8896
|
};
|
|
8174
8897
|
}
|
|
8175
8898
|
function makeCandidate(format, preview, baselineBytes) {
|
|
8176
|
-
const bytes = (0,
|
|
8899
|
+
const bytes = (0, import_shared5.utf8ByteLength)(preview);
|
|
8177
8900
|
const ratio = baselineBytes === 0 ? 0 : 1 - bytes / baselineBytes;
|
|
8178
8901
|
return {
|
|
8179
8902
|
format,
|
|
@@ -8197,31 +8920,35 @@ var TRANSFORM_FORMAT_LABELS = {
|
|
|
8197
8920
|
0 && (module.exports = {
|
|
8198
8921
|
ANONYMOUS_ACTOR,
|
|
8199
8922
|
APICIRCLE_FOLDER_EXPORT_FORMAT,
|
|
8200
|
-
ATTACHMENTS_DIR,
|
|
8201
8923
|
DESKTOP_APP_ORIGIN,
|
|
8202
8924
|
EMPTY_UNPUSHED_SUMMARY,
|
|
8203
8925
|
HTTP_HEADERS_MAP,
|
|
8204
8926
|
OAuth2TokenError,
|
|
8205
8927
|
PlanRunDeniedError,
|
|
8928
|
+
REGISTRY_JSON_PATH,
|
|
8206
8929
|
RemoteWorkspaceParseError,
|
|
8207
8930
|
TRANSFORM_FORMAT_LABELS,
|
|
8208
8931
|
WORKSPACE_DIR,
|
|
8209
|
-
|
|
8932
|
+
appendReleaseEntry,
|
|
8210
8933
|
applyAuth,
|
|
8211
8934
|
applyAwsSigV4,
|
|
8212
8935
|
applyContentTypeForBodyType,
|
|
8936
|
+
applyLinkedEnvironmentOverrides,
|
|
8213
8937
|
applyLinkedUpdate,
|
|
8214
8938
|
applyMerge,
|
|
8215
8939
|
applyMutation,
|
|
8216
8940
|
applyPathParams,
|
|
8217
8941
|
assertNoPlaintextCredentials,
|
|
8218
8942
|
attachmentPath,
|
|
8943
|
+
attachmentsDir,
|
|
8219
8944
|
buildAuthorizeUrl,
|
|
8220
8945
|
buildAutoHeaders,
|
|
8221
8946
|
buildDigestAuthHeader,
|
|
8222
8947
|
buildHawkAuthHeader,
|
|
8948
|
+
buildLinkedSnapshot,
|
|
8223
8949
|
buildNtlmType1Negotiate,
|
|
8224
8950
|
buildNtlmType3Authenticate,
|
|
8951
|
+
buildReleaseEntry,
|
|
8225
8952
|
buildRequest,
|
|
8226
8953
|
buildScope,
|
|
8227
8954
|
collectAttachmentSlots,
|
|
@@ -8235,6 +8962,7 @@ var TRANSFORM_FORMAT_LABELS = {
|
|
|
8235
8962
|
composeUrl,
|
|
8236
8963
|
composeUrlWithQuery,
|
|
8237
8964
|
computeCodeChallenge,
|
|
8965
|
+
computeRequestOverridePatch,
|
|
8238
8966
|
computeThreeWayDiff,
|
|
8239
8967
|
computeTransformSavings,
|
|
8240
8968
|
decryptString,
|
|
@@ -8247,6 +8975,7 @@ var TRANSFORM_FORMAT_LABELS = {
|
|
|
8247
8975
|
exportKey,
|
|
8248
8976
|
extractContext,
|
|
8249
8977
|
fetchOAuth2Token,
|
|
8978
|
+
fetchRemoteWorkspaceJson,
|
|
8250
8979
|
findPathPlaceholders,
|
|
8251
8980
|
generateAesKey,
|
|
8252
8981
|
generateCodeVerifier,
|
|
@@ -8264,14 +8993,18 @@ var TRANSFORM_FORMAT_LABELS = {
|
|
|
8264
8993
|
hasUnpushedChanges,
|
|
8265
8994
|
importApicircleFolderInto,
|
|
8266
8995
|
importKey,
|
|
8996
|
+
initSecretCrypto,
|
|
8267
8997
|
isApicircleEnvironment,
|
|
8268
8998
|
isApicircleFolderExport,
|
|
8269
8999
|
isDesktop,
|
|
9000
|
+
isEmptyOverridePatch,
|
|
8270
9001
|
isInsomniaExport,
|
|
8271
9002
|
isPostmanEnvironment,
|
|
8272
9003
|
isPostmanV2Collection,
|
|
8273
9004
|
isValidSemver,
|
|
9005
|
+
ledgerFromProbe,
|
|
8274
9006
|
lookup,
|
|
9007
|
+
mergeRequestOverride,
|
|
8275
9008
|
mergeWithAutoHeaders,
|
|
8276
9009
|
normalizeContentType,
|
|
8277
9010
|
parseApicircleEnvironment,
|
|
@@ -8282,12 +9015,15 @@ var TRANSFORM_FORMAT_LABELS = {
|
|
|
8282
9015
|
parseDigestChallenge,
|
|
8283
9016
|
parseGraphqlSchema,
|
|
8284
9017
|
parseInsomniaCollection,
|
|
9018
|
+
parseLinkedWorkspaceJson,
|
|
8285
9019
|
parseNtlmType2Challenge,
|
|
8286
9020
|
parsePostmanCollection,
|
|
8287
9021
|
parsePostmanEnvironment,
|
|
9022
|
+
parseRegistryActiveId,
|
|
8288
9023
|
parseSemver,
|
|
8289
9024
|
parseUrlQuery,
|
|
8290
9025
|
parseWorkspaceJson,
|
|
9026
|
+
plaintextEnvMap,
|
|
8291
9027
|
pollDeviceFlow,
|
|
8292
9028
|
preSendValidation,
|
|
8293
9029
|
previewLinkedUpdate,
|
|
@@ -8300,6 +9036,7 @@ var TRANSFORM_FORMAT_LABELS = {
|
|
|
8300
9036
|
requestRunToExecutionResult,
|
|
8301
9037
|
resolveInheritedAuth,
|
|
8302
9038
|
resolvePlanRef,
|
|
9039
|
+
resolveRequestForExecution,
|
|
8303
9040
|
resolveString,
|
|
8304
9041
|
resolveStringMap,
|
|
8305
9042
|
runAssertions,
|
|
@@ -8321,7 +9058,9 @@ var TRANSFORM_FORMAT_LABELS = {
|
|
|
8321
9058
|
toYaml,
|
|
8322
9059
|
tokenizeCurl,
|
|
8323
9060
|
tryParsePayload,
|
|
9061
|
+
unlockSecretCrypto,
|
|
8324
9062
|
validateBranchName,
|
|
9063
|
+
workspaceJsonPath,
|
|
8325
9064
|
yankRelease
|
|
8326
9065
|
});
|
|
8327
9066
|
//# sourceMappingURL=index.cjs.map
|