@apicircle/core 1.0.5 → 1.0.7

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/dist/index.js CHANGED
@@ -2943,6 +2943,9 @@ function resolveLocation(from, location) {
2943
2943
  return null;
2944
2944
  }
2945
2945
  }
2946
+ function isBrowserRuntime() {
2947
+ return typeof window !== "undefined" && typeof window.document !== "undefined";
2948
+ }
2946
2949
  async function executeRequest(req, opts = {}) {
2947
2950
  const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
2948
2951
  const timeoutMs = opts.timeoutMs === void 0 ? DEFAULT_TIMEOUT_MS : opts.timeoutMs;
@@ -2967,6 +2970,7 @@ async function executeRequest(req, opts = {}) {
2967
2970
  () => controller.abort(new Error(`Request timed out after ${timeoutMs}ms`)),
2968
2971
  timeoutMs
2969
2972
  );
2973
+ const redirectMode = isBrowserRuntime() ? "follow" : "manual";
2970
2974
  let currentUrl = builtRequest.url;
2971
2975
  let currentHeaders = { ...builtRequest.headers };
2972
2976
  let currentMethod = builtRequest.method;
@@ -2976,7 +2980,7 @@ async function executeRequest(req, opts = {}) {
2976
2980
  headers: currentHeaders,
2977
2981
  body: currentBody,
2978
2982
  signal: controller.signal,
2979
- redirect: "manual"
2983
+ redirect: redirectMode
2980
2984
  });
2981
2985
  let redirectCount = 0;
2982
2986
  while (REDIRECT_STATUSES.has(response.status) && redirectCount < MAX_REDIRECTS) {
@@ -3002,7 +3006,7 @@ async function executeRequest(req, opts = {}) {
3002
3006
  headers: currentHeaders,
3003
3007
  body: currentBody,
3004
3008
  signal: controller.signal,
3005
- redirect: "manual"
3009
+ redirect: redirectMode
3006
3010
  });
3007
3011
  redirectCount++;
3008
3012
  }
@@ -3969,6 +3973,699 @@ function parseAuth2(auth, warnings, name) {
3969
3973
  }
3970
3974
  }
3971
3975
 
3976
+ // src/import/apicircleFolder.ts
3977
+ import { generateId } from "@apicircle/shared";
3978
+
3979
+ // src/export/folderExportCredentials.ts
3980
+ function collectFolderExportCredentials(envelope) {
3981
+ const out = [];
3982
+ if (envelope.folder.auth) {
3983
+ out.push(
3984
+ ...authCredentialFields(envelope.folder.auth).map(
3985
+ (f) => buildCredential(
3986
+ "root-folder",
3987
+ envelope.source.folderId,
3988
+ envelope.folder.name,
3989
+ envelope.folder.auth,
3990
+ f
3991
+ )
3992
+ )
3993
+ );
3994
+ }
3995
+ for (const sub of envelope.folder.subfolders) {
3996
+ if (!sub.auth) continue;
3997
+ out.push(
3998
+ ...authCredentialFields(sub.auth).map(
3999
+ (f) => buildCredential("subfolder", sub.id, sub.name, sub.auth, f)
4000
+ )
4001
+ );
4002
+ }
4003
+ for (const req of envelope.folder.requests) {
4004
+ out.push(
4005
+ ...authCredentialFields(req.auth).map(
4006
+ (f) => buildCredential("request", req.id, req.name, req.auth, f)
4007
+ )
4008
+ );
4009
+ }
4010
+ return out.sort(credentialCompare);
4011
+ }
4012
+ function redactFolderExportCredentials(envelope, includeIds = /* @__PURE__ */ new Set()) {
4013
+ const next = {
4014
+ ...envelope,
4015
+ folder: {
4016
+ ...envelope.folder,
4017
+ auth: envelope.folder.auth ? redactAuthForScope(
4018
+ envelope.folder.auth,
4019
+ credentialIdsFor("root-folder", envelope.source.folderId, envelope.folder.auth),
4020
+ includeIds
4021
+ ) : envelope.folder.auth,
4022
+ subfolders: envelope.folder.subfolders.map((sub) => {
4023
+ if (!sub.auth) return sub;
4024
+ const ids = credentialIdsFor("subfolder", sub.id, sub.auth);
4025
+ return {
4026
+ ...sub,
4027
+ auth: redactAuthForScope(sub.auth, ids, includeIds)
4028
+ };
4029
+ }),
4030
+ requests: envelope.folder.requests.map((req) => ({
4031
+ ...req,
4032
+ auth: redactAuthForScope(
4033
+ req.auth,
4034
+ credentialIdsFor("request", req.id, req.auth),
4035
+ includeIds
4036
+ )
4037
+ }))
4038
+ }
4039
+ };
4040
+ return next;
4041
+ }
4042
+ function authCredentialFields(auth) {
4043
+ switch (auth.type) {
4044
+ case "none":
4045
+ case "inherit":
4046
+ case "custom-header":
4047
+ return [];
4048
+ case "basic":
4049
+ return [{ field: "password", label: "Basic \xB7 password" }];
4050
+ case "bearer":
4051
+ return auth.token ? [{ field: "token", label: "Bearer \xB7 token" }] : [];
4052
+ case "api-key":
4053
+ return auth.value ? [{ field: "value", label: "API key \xB7 value" }] : [];
4054
+ case "digest":
4055
+ return [{ field: "password", label: "Digest \xB7 password" }];
4056
+ case "ntlm":
4057
+ return [{ field: "password", label: "NTLM \xB7 password" }];
4058
+ case "hawk":
4059
+ return auth.hawkKey ? [{ field: "hawkKey", label: "Hawk \xB7 hawkKey" }] : [];
4060
+ case "jwt-bearer":
4061
+ return [
4062
+ ...auth.secretOrKey ? [{ field: "secretOrKey", label: "JWT \xB7 secretOrKey" }] : [],
4063
+ ...auth.token ? [{ field: "token", label: "JWT \xB7 token" }] : []
4064
+ ];
4065
+ case "aws-sigv4":
4066
+ return [
4067
+ ...auth.secretAccessKey ? [{ field: "secretAccessKey", label: "AWS SigV4 \xB7 secretAccessKey" }] : [],
4068
+ ...auth.sessionToken ? [{ field: "sessionToken", label: "AWS SigV4 \xB7 sessionToken" }] : []
4069
+ ];
4070
+ case "oauth2-client-credentials":
4071
+ case "oauth2-auth-code":
4072
+ case "oauth2-pkce":
4073
+ return [
4074
+ ...auth.clientSecret ? [{ field: "clientSecret", label: `${auth.type} \xB7 clientSecret` }] : [],
4075
+ ...auth.accessToken ? [{ field: "accessToken", label: `${auth.type} \xB7 accessToken` }] : [],
4076
+ ...auth.refreshToken ? [{ field: "refreshToken", label: `${auth.type} \xB7 refreshToken` }] : []
4077
+ ];
4078
+ case "oauth2-password":
4079
+ return [
4080
+ ...auth.clientSecret ? [{ field: "clientSecret", label: "oauth2-password \xB7 clientSecret" }] : [],
4081
+ ...auth.password ? [{ field: "password", label: "oauth2-password \xB7 password" }] : [],
4082
+ ...auth.accessToken ? [{ field: "accessToken", label: "oauth2-password \xB7 accessToken" }] : [],
4083
+ ...auth.refreshToken ? [{ field: "refreshToken", label: "oauth2-password \xB7 refreshToken" }] : []
4084
+ ];
4085
+ case "oauth2-implicit":
4086
+ return auth.accessToken ? [{ field: "accessToken", label: "oauth2-implicit \xB7 accessToken" }] : [];
4087
+ case "oauth2-device":
4088
+ return [
4089
+ ...auth.accessToken ? [{ field: "accessToken", label: "oauth2-device \xB7 accessToken" }] : [],
4090
+ ...auth.refreshToken ? [{ field: "refreshToken", label: "oauth2-device \xB7 refreshToken" }] : []
4091
+ ];
4092
+ default:
4093
+ return [];
4094
+ }
4095
+ }
4096
+ function buildCredential(scope, ownerId, ownerName, auth, desc) {
4097
+ const prefix = scope === "request" ? "request" : "folder";
4098
+ return {
4099
+ id: `${prefix}:${ownerId}.${auth.type}.${desc.field}`,
4100
+ scope,
4101
+ authType: auth.type,
4102
+ field: desc.field,
4103
+ label: desc.label,
4104
+ ownerName,
4105
+ ownerId
4106
+ };
4107
+ }
4108
+ function credentialIdsFor(scope, ownerId, auth) {
4109
+ const ids = /* @__PURE__ */ new Map();
4110
+ const prefix = scope === "request" ? "request" : "folder";
4111
+ for (const desc of authCredentialFields(auth)) {
4112
+ ids.set(desc.field, `${prefix}:${ownerId}.${auth.type}.${desc.field}`);
4113
+ }
4114
+ return ids;
4115
+ }
4116
+ function redactAuthForScope(auth, ids, includeIds) {
4117
+ const shouldBlank = (field) => {
4118
+ const id = ids.get(field);
4119
+ return !!id && !includeIds.has(id);
4120
+ };
4121
+ switch (auth.type) {
4122
+ case "none":
4123
+ case "inherit":
4124
+ case "custom-header":
4125
+ return auth;
4126
+ case "basic":
4127
+ return shouldBlank("password") ? { ...auth, password: "" } : auth;
4128
+ case "bearer":
4129
+ return shouldBlank("token") ? { ...auth, token: "" } : auth;
4130
+ case "api-key":
4131
+ return shouldBlank("value") ? { ...auth, value: "" } : auth;
4132
+ case "digest":
4133
+ return shouldBlank("password") ? { ...auth, password: "" } : auth;
4134
+ case "ntlm":
4135
+ return shouldBlank("password") ? { ...auth, password: "" } : auth;
4136
+ case "hawk":
4137
+ return shouldBlank("hawkKey") ? { ...auth, hawkKey: "" } : auth;
4138
+ case "jwt-bearer":
4139
+ return {
4140
+ ...auth,
4141
+ secretOrKey: shouldBlank("secretOrKey") ? "" : auth.secretOrKey,
4142
+ token: shouldBlank("token") ? "" : auth.token
4143
+ };
4144
+ case "aws-sigv4":
4145
+ return {
4146
+ ...auth,
4147
+ secretAccessKey: shouldBlank("secretAccessKey") ? "" : auth.secretAccessKey,
4148
+ sessionToken: shouldBlank("sessionToken") ? "" : auth.sessionToken
4149
+ };
4150
+ case "oauth2-client-credentials":
4151
+ case "oauth2-auth-code":
4152
+ case "oauth2-pkce":
4153
+ return {
4154
+ ...auth,
4155
+ clientSecret: shouldBlank("clientSecret") ? "" : auth.clientSecret,
4156
+ accessToken: shouldBlank("accessToken") ? "" : auth.accessToken,
4157
+ refreshToken: shouldBlank("refreshToken") ? "" : auth.refreshToken
4158
+ };
4159
+ case "oauth2-password":
4160
+ return {
4161
+ ...auth,
4162
+ clientSecret: shouldBlank("clientSecret") ? "" : auth.clientSecret,
4163
+ password: shouldBlank("password") ? "" : auth.password,
4164
+ accessToken: shouldBlank("accessToken") ? "" : auth.accessToken,
4165
+ refreshToken: shouldBlank("refreshToken") ? "" : auth.refreshToken
4166
+ };
4167
+ case "oauth2-implicit":
4168
+ return {
4169
+ ...auth,
4170
+ accessToken: shouldBlank("accessToken") ? "" : auth.accessToken
4171
+ };
4172
+ case "oauth2-device":
4173
+ return {
4174
+ ...auth,
4175
+ accessToken: shouldBlank("accessToken") ? "" : auth.accessToken,
4176
+ refreshToken: shouldBlank("refreshToken") ? "" : auth.refreshToken
4177
+ };
4178
+ default:
4179
+ return auth;
4180
+ }
4181
+ }
4182
+ function scopeRank(scope) {
4183
+ if (scope === "root-folder") return 0;
4184
+ if (scope === "subfolder") return 1;
4185
+ return 2;
4186
+ }
4187
+ function credentialCompare(a, b) {
4188
+ const r = scopeRank(a.scope) - scopeRank(b.scope);
4189
+ if (r !== 0) return r;
4190
+ return a.ownerName.localeCompare(b.ownerName, void 0, { sensitivity: "base" });
4191
+ }
4192
+
4193
+ // src/export/folderExport.ts
4194
+ var APICIRCLE_FOLDER_EXPORT_FORMAT = "apicircle.folder/v1";
4195
+ function collectFolderExport(args) {
4196
+ const { synced, folderId } = args;
4197
+ const root = synced.collections.folders[folderId];
4198
+ if (!root) return null;
4199
+ const now = args.now ?? (/* @__PURE__ */ new Date()).toISOString();
4200
+ const appVersion = args.appVersion ?? "apicircle-studio";
4201
+ const folderIds = /* @__PURE__ */ new Set([folderId]);
4202
+ let grew = true;
4203
+ while (grew) {
4204
+ grew = false;
4205
+ for (const f of Object.values(synced.collections.folders)) {
4206
+ if (folderIds.has(f.id)) continue;
4207
+ if (f.parentId && folderIds.has(f.parentId)) {
4208
+ folderIds.add(f.id);
4209
+ grew = true;
4210
+ }
4211
+ }
4212
+ }
4213
+ const subfolders = [];
4214
+ for (const f of Object.values(synced.collections.folders)) {
4215
+ if (f.id !== folderId && folderIds.has(f.id)) subfolders.push(cloneFolder(f));
4216
+ }
4217
+ const requests = [];
4218
+ for (const r of Object.values(synced.collections.requests)) {
4219
+ if (r.folderId && folderIds.has(r.folderId)) requests.push(cloneRequest(r));
4220
+ }
4221
+ const dependencies = collectDependencies(synced, requests);
4222
+ const envelope = {
4223
+ format: APICIRCLE_FOLDER_EXPORT_FORMAT,
4224
+ exportedAt: now,
4225
+ appVersion,
4226
+ source: {
4227
+ workspaceId: synced.workspaceId,
4228
+ folderId,
4229
+ folderName: root.name
4230
+ },
4231
+ folder: {
4232
+ name: root.name,
4233
+ auth: root.auth,
4234
+ subfolders,
4235
+ requests
4236
+ },
4237
+ dependencies
4238
+ };
4239
+ const report = buildReport(envelope);
4240
+ return { envelope, report };
4241
+ }
4242
+ function serializeFolderExport(envelope) {
4243
+ return JSON.stringify(envelope, null, 2);
4244
+ }
4245
+ function suggestFolderExportFilename(envelope) {
4246
+ const slug = envelope.folder.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
4247
+ const base = slug || "folder";
4248
+ return `${base}.apicircle.json`;
4249
+ }
4250
+ function cloneFolder(f) {
4251
+ return {
4252
+ ...f,
4253
+ auth: f.auth ? { ...f.auth } : void 0
4254
+ };
4255
+ }
4256
+ function cloneRequest(r) {
4257
+ return {
4258
+ ...r,
4259
+ headers: r.headers.map((h) => ({ ...h })),
4260
+ query: r.query.map((q) => ({ ...q })),
4261
+ pathParams: r.pathParams ? { ...r.pathParams } : void 0,
4262
+ cookies: r.cookies ? r.cookies.map((c) => ({ ...c })) : void 0,
4263
+ body: cloneBody(r.body),
4264
+ auth: { ...r.auth },
4265
+ contextVars: r.contextVars.map((v) => ({ ...v })),
4266
+ extractions: r.extractions.map((e) => ({ ...e })),
4267
+ assertions: r.assertions.map((a) => ({ ...a }))
4268
+ };
4269
+ }
4270
+ function cloneBody(body) {
4271
+ if (body.type === "form-data") {
4272
+ return {
4273
+ ...body,
4274
+ formRows: body.formRows?.map((row) => ({ ...row })) ?? body.formRows
4275
+ };
4276
+ }
4277
+ if (body.type === "binary") {
4278
+ return {
4279
+ ...body,
4280
+ attachment: body.attachment ? { ...body.attachment } : void 0
4281
+ };
4282
+ }
4283
+ return { ...body };
4284
+ }
4285
+ function collectDependencies(synced, requests) {
4286
+ const schemaIds = /* @__PURE__ */ new Set();
4287
+ const graphqlIds = /* @__PURE__ */ new Set();
4288
+ const fileIds = /* @__PURE__ */ new Set();
4289
+ for (const r of requests) {
4290
+ if (r.bodySchemaId) schemaIds.add(r.bodySchemaId);
4291
+ if (r.graphqlSchemaId) graphqlIds.add(r.graphqlSchemaId);
4292
+ if (r.body.type === "binary" && r.body.attachment?.globalFileAssetId) {
4293
+ fileIds.add(r.body.attachment.globalFileAssetId);
4294
+ }
4295
+ if (r.body.type === "form-data" && r.body.formRows) {
4296
+ for (const row of r.body.formRows) {
4297
+ if (row.kind === "file" && row.globalFileAssetId) fileIds.add(row.globalFileAssetId);
4298
+ }
4299
+ }
4300
+ }
4301
+ const assets = synced.globalAssets;
4302
+ const schemas = [];
4303
+ for (const id of schemaIds) {
4304
+ const s = assets.schemas[id];
4305
+ if (s) schemas.push({ ...s });
4306
+ }
4307
+ const graphql = [];
4308
+ for (const id of graphqlIds) {
4309
+ const g = assets.graphql[id];
4310
+ if (g) graphql.push({ ...g });
4311
+ }
4312
+ const files = [];
4313
+ for (const id of fileIds) {
4314
+ const f = assets.files?.[id];
4315
+ if (f) files.push({ ...f });
4316
+ }
4317
+ schemas.sort(byNameThenId);
4318
+ graphql.sort(byNameThenId);
4319
+ files.sort(byNameThenId);
4320
+ return { schemas, graphql, files };
4321
+ }
4322
+ function byNameThenId(a, b) {
4323
+ const c = a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
4324
+ return c !== 0 ? c : a.id.localeCompare(b.id);
4325
+ }
4326
+ function buildReport(envelope) {
4327
+ const subfolderCount = envelope.folder.subfolders.length;
4328
+ const requestCount = envelope.folder.requests.length;
4329
+ const totalFolderCount = subfolderCount + 1;
4330
+ const credentials = collectFolderExportCredentials(envelope);
4331
+ return {
4332
+ folderName: envelope.folder.name,
4333
+ requestCount,
4334
+ subfolderCount,
4335
+ totalFolderCount,
4336
+ dependencies: {
4337
+ schemas: envelope.dependencies.schemas.map((s) => ({ id: s.id, name: s.name })),
4338
+ graphql: envelope.dependencies.graphql.map((g) => ({
4339
+ id: g.id,
4340
+ name: g.name,
4341
+ kind: g.kind
4342
+ })),
4343
+ files: envelope.dependencies.files.map((f) => ({
4344
+ id: f.id,
4345
+ name: f.name,
4346
+ filename: f.filename,
4347
+ size: f.size,
4348
+ mimeType: f.mimeType
4349
+ }))
4350
+ },
4351
+ hasDependencies: envelope.dependencies.schemas.length > 0 || envelope.dependencies.graphql.length > 0 || envelope.dependencies.files.length > 0,
4352
+ credentials,
4353
+ hasCredentials: credentials.length > 0
4354
+ };
4355
+ }
4356
+
4357
+ // src/import/apicircleFolder.ts
4358
+ function isApicircleFolderExport(doc) {
4359
+ if (!doc || typeof doc !== "object") return false;
4360
+ const d = doc;
4361
+ return d.format === APICIRCLE_FOLDER_EXPORT_FORMAT;
4362
+ }
4363
+ function parseApicircleFolderExport(input, options = {}) {
4364
+ let doc;
4365
+ try {
4366
+ doc = JSON.parse(input);
4367
+ } catch (err) {
4368
+ throw new Error(`Couldn't parse JSON: ${err instanceof Error ? err.message : String(err)}`);
4369
+ }
4370
+ return parseApicircleFolderExportDoc(doc, options);
4371
+ }
4372
+ function parseApicircleFolderExportDoc(doc, options = {}) {
4373
+ const id = options.idGenerator ?? generateId;
4374
+ if (!isApicircleFolderExport(doc)) {
4375
+ throw new Error(
4376
+ `Unsupported format. Expected an API Circle folder export ("format": "${APICIRCLE_FOLDER_EXPORT_FORMAT}").`
4377
+ );
4378
+ }
4379
+ const envelope = doc;
4380
+ validateEnvelopeShape(envelope);
4381
+ const warnings = [];
4382
+ const folderIdMap = /* @__PURE__ */ new Map();
4383
+ folderIdMap.set(envelope.source.folderId, id());
4384
+ for (const f of envelope.folder.subfolders) folderIdMap.set(f.id, id());
4385
+ const requestIdMap = /* @__PURE__ */ new Map();
4386
+ for (const r of envelope.folder.requests) requestIdMap.set(r.id, id());
4387
+ const schemaIdMap = /* @__PURE__ */ new Map();
4388
+ for (const s of envelope.dependencies.schemas) schemaIdMap.set(s.id, id());
4389
+ const graphqlIdMap = /* @__PURE__ */ new Map();
4390
+ for (const g of envelope.dependencies.graphql) graphqlIdMap.set(g.id, id());
4391
+ const fileIdMap = /* @__PURE__ */ new Map();
4392
+ for (const f of envelope.dependencies.files) fileIdMap.set(f.id, id());
4393
+ const rootFolderId = folderIdMap.get(envelope.source.folderId);
4394
+ const subfolders = envelope.folder.subfolders.map((f) => {
4395
+ const newId = folderIdMap.get(f.id);
4396
+ let newParentId;
4397
+ if (f.parentId === null) {
4398
+ newParentId = rootFolderId;
4399
+ } else {
4400
+ const mapped = folderIdMap.get(f.parentId);
4401
+ if (!mapped) {
4402
+ warnings.push(
4403
+ `Subfolder "${f.name}" referenced parentId "${f.parentId}" that wasn't present in the export \u2014 reattached under "${envelope.folder.name}".`
4404
+ );
4405
+ newParentId = rootFolderId;
4406
+ } else {
4407
+ newParentId = mapped;
4408
+ }
4409
+ }
4410
+ return {
4411
+ ...f,
4412
+ id: newId,
4413
+ parentId: newParentId,
4414
+ auth: f.auth ? { ...f.auth } : void 0
4415
+ };
4416
+ });
4417
+ const schemas = envelope.dependencies.schemas.map((s) => ({
4418
+ ...s,
4419
+ id: schemaIdMap.get(s.id)
4420
+ }));
4421
+ const graphql = envelope.dependencies.graphql.map((g) => ({
4422
+ ...g,
4423
+ id: graphqlIdMap.get(g.id)
4424
+ }));
4425
+ const files = envelope.dependencies.files.map((f) => ({
4426
+ ...f,
4427
+ id: fileIdMap.get(f.id)
4428
+ }));
4429
+ const requests = envelope.folder.requests.map((r) => {
4430
+ const newId = requestIdMap.get(r.id);
4431
+ let newFolderId;
4432
+ if (r.folderId === null) {
4433
+ newFolderId = rootFolderId;
4434
+ } else {
4435
+ const mapped = folderIdMap.get(r.folderId);
4436
+ if (!mapped) {
4437
+ warnings.push(
4438
+ `Request "${r.name}" referenced folderId "${r.folderId}" that wasn't present in the export \u2014 reattached under "${envelope.folder.name}".`
4439
+ );
4440
+ newFolderId = rootFolderId;
4441
+ } else {
4442
+ newFolderId = mapped;
4443
+ }
4444
+ }
4445
+ const bodySchemaId = remapDependencyRef(
4446
+ r.bodySchemaId,
4447
+ schemaIdMap,
4448
+ `Request "${r.name}".bodySchemaId`,
4449
+ warnings
4450
+ );
4451
+ const graphqlSchemaId = remapDependencyRef(
4452
+ r.graphqlSchemaId,
4453
+ graphqlIdMap,
4454
+ `Request "${r.name}".graphqlSchemaId`,
4455
+ warnings
4456
+ );
4457
+ return {
4458
+ ...r,
4459
+ id: newId,
4460
+ folderId: newFolderId,
4461
+ bodySchemaId,
4462
+ graphqlSchemaId,
4463
+ headers: r.headers.map((h) => ({ ...h })),
4464
+ query: r.query.map((q) => ({ ...q })),
4465
+ pathParams: r.pathParams ? { ...r.pathParams } : void 0,
4466
+ cookies: r.cookies ? r.cookies.map((c) => ({ ...c })) : void 0,
4467
+ body: remapBodyFileRefs(r.body, fileIdMap, r.name, warnings),
4468
+ auth: { ...r.auth },
4469
+ contextVars: r.contextVars.map((v) => ({ ...v })),
4470
+ extractions: r.extractions.map((e) => ({ ...e })),
4471
+ assertions: r.assertions.map((a) => ({ ...a }))
4472
+ };
4473
+ });
4474
+ return {
4475
+ rootFolder: {
4476
+ id: rootFolderId,
4477
+ name: envelope.folder.name,
4478
+ auth: envelope.folder.auth ? { ...envelope.folder.auth } : void 0
4479
+ },
4480
+ subfolders,
4481
+ requests,
4482
+ dependencies: { schemas, graphql, files },
4483
+ sourceFolderName: envelope.source.folderName,
4484
+ warnings
4485
+ };
4486
+ }
4487
+ function validateEnvelopeShape(envelope) {
4488
+ if (!envelope.folder || typeof envelope.folder !== "object") {
4489
+ throw new Error('API Circle folder export is missing the "folder" section.');
4490
+ }
4491
+ if (typeof envelope.folder.name !== "string" || envelope.folder.name.length === 0) {
4492
+ throw new Error('API Circle folder export must have a non-empty "folder.name".');
4493
+ }
4494
+ if (!Array.isArray(envelope.folder.subfolders)) {
4495
+ throw new Error('API Circle folder export must have a "folder.subfolders" array.');
4496
+ }
4497
+ if (!Array.isArray(envelope.folder.requests)) {
4498
+ throw new Error('API Circle folder export must have a "folder.requests" array.');
4499
+ }
4500
+ if (!envelope.dependencies || typeof envelope.dependencies !== "object") {
4501
+ throw new Error('API Circle folder export is missing the "dependencies" section.');
4502
+ }
4503
+ if (!Array.isArray(envelope.dependencies.schemas) || !Array.isArray(envelope.dependencies.graphql) || !Array.isArray(envelope.dependencies.files)) {
4504
+ throw new Error(
4505
+ 'API Circle folder export "dependencies" must have schemas / graphql / files arrays.'
4506
+ );
4507
+ }
4508
+ if (!envelope.source || typeof envelope.source !== "object") {
4509
+ throw new Error('API Circle folder export is missing the "source" section.');
4510
+ }
4511
+ if (typeof envelope.source.folderId !== "string" || typeof envelope.source.folderName !== "string") {
4512
+ throw new Error('API Circle folder export "source" must include "folderId" and "folderName".');
4513
+ }
4514
+ }
4515
+ function remapDependencyRef(value, map, label, warnings) {
4516
+ if (value === null || value === void 0) return value;
4517
+ const mapped = map.get(value);
4518
+ if (mapped) return mapped;
4519
+ warnings.push(
4520
+ `${label} referenced a dependency ("${value}") that wasn't embedded in the export \u2014 reference dropped on import.`
4521
+ );
4522
+ return null;
4523
+ }
4524
+ function remapBodyFileRefs(body, fileIdMap, requestName, warnings) {
4525
+ if (body.type === "binary") {
4526
+ if (!body.attachment) return { ...body };
4527
+ const oldId = body.attachment.globalFileAssetId;
4528
+ let nextGlobalFileAssetId = oldId;
4529
+ if (oldId) {
4530
+ const mapped = fileIdMap.get(oldId);
4531
+ if (mapped) {
4532
+ nextGlobalFileAssetId = mapped;
4533
+ } else {
4534
+ warnings.push(
4535
+ `Request "${requestName}".body.attachment referenced file asset "${oldId}" that wasn't embedded in the export \u2014 re-attach the file after import.`
4536
+ );
4537
+ nextGlobalFileAssetId = null;
4538
+ }
4539
+ }
4540
+ return {
4541
+ ...body,
4542
+ attachment: {
4543
+ ...body.attachment,
4544
+ // Reset slotId — the destination workspace owns its own slots.
4545
+ slotId: null,
4546
+ globalFileAssetId: nextGlobalFileAssetId
4547
+ }
4548
+ };
4549
+ }
4550
+ if (body.type === "form-data") {
4551
+ const formRows = body.formRows?.map((row) => {
4552
+ if (row.kind !== "file") return { ...row };
4553
+ const oldId = row.globalFileAssetId;
4554
+ let nextGlobalFileAssetId = oldId;
4555
+ if (oldId) {
4556
+ const mapped = fileIdMap.get(oldId);
4557
+ if (mapped) {
4558
+ nextGlobalFileAssetId = mapped;
4559
+ } else {
4560
+ warnings.push(
4561
+ `Request "${requestName}" form-data row "${row.key}" referenced file asset "${oldId}" that wasn't embedded in the export \u2014 re-attach the file after import.`
4562
+ );
4563
+ nextGlobalFileAssetId = null;
4564
+ }
4565
+ }
4566
+ return {
4567
+ ...row,
4568
+ slotId: null,
4569
+ globalFileAssetId: nextGlobalFileAssetId
4570
+ };
4571
+ });
4572
+ return { ...body, formRows };
4573
+ }
4574
+ return { ...body };
4575
+ }
4576
+
4577
+ // src/import/apicircleEnvironment.ts
4578
+ function isApicircleEnvironment(doc) {
4579
+ if (!doc || typeof doc !== "object") return false;
4580
+ const d = doc;
4581
+ return (d.apicircleEnvironment === 1 || d.apicircleEnvironment === 2) && typeof d.name === "string" && Array.isArray(d.variables);
4582
+ }
4583
+ function parseApicircleEnvironment(input) {
4584
+ let doc;
4585
+ try {
4586
+ doc = JSON.parse(input);
4587
+ } catch (err) {
4588
+ throw new Error(`Couldn't parse JSON: ${err instanceof Error ? err.message : String(err)}`);
4589
+ }
4590
+ return parseApicircleEnvironmentDoc(doc);
4591
+ }
4592
+ function parseApicircleEnvironmentDoc(doc) {
4593
+ if (!isApicircleEnvironment(doc)) {
4594
+ throw new Error(
4595
+ 'Unsupported format. Expected an API Circle environment export ("apicircleEnvironment": 1 or 2).'
4596
+ );
4597
+ }
4598
+ const name = doc.name.trim();
4599
+ if (!name) {
4600
+ throw new Error('API Circle environment export must have a non-empty "name".');
4601
+ }
4602
+ const payloadVersion = doc.apicircleEnvironment;
4603
+ const warnings = [];
4604
+ const variables = [];
4605
+ const encryptedBindingHints = [];
4606
+ for (let i = 0; i < doc.variables.length; i += 1) {
4607
+ const raw = doc.variables[i];
4608
+ if (!raw || typeof raw !== "object") {
4609
+ warnings.push(`Row #${i + 1} was not an object \u2014 dropped.`);
4610
+ continue;
4611
+ }
4612
+ const key = typeof raw.key === "string" ? raw.key.trim() : "";
4613
+ if (!key) {
4614
+ warnings.push(`Row #${i + 1} had no key \u2014 dropped.`);
4615
+ continue;
4616
+ }
4617
+ if (raw.encrypted === true) {
4618
+ const secretKeyId = typeof raw.secretKeyId === "string" ? raw.secretKeyId : "";
4619
+ const labelFromSecret = readLabelFromSecretField(raw.secret);
4620
+ const ciphertext = payloadVersion === 2 && typeof raw.value === "string" && raw.value.startsWith("enc:") ? raw.value : null;
4621
+ const salt = payloadVersion === 2 ? readSaltFromSecretField(raw.secret) : null;
4622
+ if (!secretKeyId && !labelFromSecret) {
4623
+ warnings.push(
4624
+ `"${key}" was marked encrypted but carried no secretKeyId and no secret label \u2014 imported as an empty plain variable. Re-bind it under Environments after import.`
4625
+ );
4626
+ variables.push({ key, value: "", encrypted: false });
4627
+ continue;
4628
+ }
4629
+ variables.push({
4630
+ key,
4631
+ value: ciphertext ?? "",
4632
+ encrypted: true,
4633
+ secretKeyId: secretKeyId || void 0
4634
+ });
4635
+ const labelFromFallback = !labelFromSecret;
4636
+ encryptedBindingHints.push({
4637
+ varKey: key,
4638
+ label: labelFromSecret ?? key,
4639
+ originSecretKeyId: secretKeyId || void 0,
4640
+ labelFromFallback,
4641
+ ciphertext,
4642
+ salt
4643
+ });
4644
+ continue;
4645
+ }
4646
+ variables.push({
4647
+ key,
4648
+ value: typeof raw.value === "string" ? raw.value : "",
4649
+ encrypted: false
4650
+ });
4651
+ }
4652
+ return { name, variables, encryptedBindingHints, payloadVersion, warnings };
4653
+ }
4654
+ function readLabelFromSecretField(field) {
4655
+ if (!field || typeof field !== "object") return null;
4656
+ const f = field;
4657
+ if (typeof f.label !== "string") return null;
4658
+ const trimmed = f.label.trim();
4659
+ return trimmed.length > 0 ? trimmed : null;
4660
+ }
4661
+ function readSaltFromSecretField(field) {
4662
+ if (!field || typeof field !== "object") return null;
4663
+ const f = field;
4664
+ if (typeof f.salt !== "string") return null;
4665
+ const trimmed = f.salt.trim();
4666
+ return trimmed.length > 0 ? trimmed : null;
4667
+ }
4668
+
3972
4669
  // src/assertions/runAssertions.ts
3973
4670
  function runAssertions(assertions, exec) {
3974
4671
  return assertions.map((a) => runOne(a, exec));
@@ -5716,7 +6413,232 @@ function structurallyEqual2(a, b) {
5716
6413
  }
5717
6414
 
5718
6415
  // src/workspace/applyMutation.ts
5719
- import { envPriorityKey, generateId } from "@apicircle/shared";
6416
+ import { envPriorityKey, generateId as generateId2 } from "@apicircle/shared";
6417
+
6418
+ // src/workspace/apicircleFolderImport.ts
6419
+ function importApicircleFolderInto(synced, parsed, parentFolderId) {
6420
+ let cur = synced;
6421
+ const schemaRemap = /* @__PURE__ */ new Map();
6422
+ const graphqlRemap = /* @__PURE__ */ new Map();
6423
+ const fileRemap = /* @__PURE__ */ new Map();
6424
+ let schemasAdded = 0;
6425
+ let schemasReused = 0;
6426
+ let graphqlAdded = 0;
6427
+ let graphqlReused = 0;
6428
+ let filesAdded = 0;
6429
+ let filesReused = 0;
6430
+ const filesRequiringReattachment = [];
6431
+ const now = (/* @__PURE__ */ new Date()).toISOString();
6432
+ for (const incoming of parsed.dependencies.schemas) {
6433
+ const existing = findMatchingSchema(cur, incoming);
6434
+ if (existing) {
6435
+ schemaRemap.set(incoming.id, existing.id);
6436
+ schemasReused += 1;
6437
+ continue;
6438
+ }
6439
+ cur = mergeGlobalSchema(cur, incoming, now);
6440
+ schemaRemap.set(incoming.id, incoming.id);
6441
+ schemasAdded += 1;
6442
+ }
6443
+ for (const incoming of parsed.dependencies.graphql) {
6444
+ const existing = findMatchingGraphQL(cur, incoming);
6445
+ if (existing) {
6446
+ graphqlRemap.set(incoming.id, existing.id);
6447
+ graphqlReused += 1;
6448
+ continue;
6449
+ }
6450
+ cur = mergeGlobalGraphQL(cur, incoming, now);
6451
+ graphqlRemap.set(incoming.id, incoming.id);
6452
+ graphqlAdded += 1;
6453
+ }
6454
+ for (const incoming of parsed.dependencies.files) {
6455
+ const existing = findMatchingFile(cur, incoming);
6456
+ if (existing) {
6457
+ fileRemap.set(incoming.id, existing.id);
6458
+ filesReused += 1;
6459
+ continue;
6460
+ }
6461
+ cur = mergeGlobalFile(cur, incoming, now);
6462
+ fileRemap.set(incoming.id, incoming.id);
6463
+ filesAdded += 1;
6464
+ filesRequiringReattachment.push(incoming.id);
6465
+ }
6466
+ const rootName = uniquifyFolderName(cur, parentFolderId, parsed.rootFolder.name);
6467
+ const root = {
6468
+ id: parsed.rootFolder.id,
6469
+ name: rootName,
6470
+ parentId: parentFolderId,
6471
+ auth: parsed.rootFolder.auth ? { ...parsed.rootFolder.auth } : void 0
6472
+ };
6473
+ cur = insertFolder(
6474
+ cur,
6475
+ root,
6476
+ /* attachToTree */
6477
+ parentFolderId === null
6478
+ );
6479
+ for (const f of parsed.subfolders) {
6480
+ cur = insertFolder(
6481
+ cur,
6482
+ f,
6483
+ /* attachToTree */
6484
+ false
6485
+ );
6486
+ }
6487
+ for (const r of parsed.requests) {
6488
+ const rewritten = {
6489
+ ...r,
6490
+ bodySchemaId: rewriteRef(r.bodySchemaId, schemaRemap),
6491
+ graphqlSchemaId: rewriteRef(r.graphqlSchemaId, graphqlRemap),
6492
+ body: rewriteBodyFileRefs(r.body, fileRemap)
6493
+ };
6494
+ cur = insertRequest(cur, rewritten);
6495
+ }
6496
+ return {
6497
+ synced: { ...cur, meta: { ...cur.meta, updatedAt: now } },
6498
+ rootFolderId: root.id,
6499
+ rootFolderName: rootName,
6500
+ counts: {
6501
+ folders: parsed.subfolders.length + 1,
6502
+ requests: parsed.requests.length,
6503
+ schemasAdded,
6504
+ schemasReused,
6505
+ graphqlAdded,
6506
+ graphqlReused,
6507
+ filesAdded,
6508
+ filesReused
6509
+ },
6510
+ filesRequiringReattachment
6511
+ };
6512
+ }
6513
+ function isFolderNameAvailable(synced, parentFolderId, name) {
6514
+ const trimmed = name.trim().toLowerCase();
6515
+ if (!trimmed) return false;
6516
+ for (const node of Object.values(synced.collections.folders)) {
6517
+ if (node.parentId !== parentFolderId) continue;
6518
+ if (node.name.trim().toLowerCase() === trimmed) return false;
6519
+ }
6520
+ return true;
6521
+ }
6522
+ function uniquifyFolderName(synced, parentFolderId, desired) {
6523
+ if (isFolderNameAvailable(synced, parentFolderId, desired)) return desired;
6524
+ let n = 2;
6525
+ while (!isFolderNameAvailable(synced, parentFolderId, `${desired} (${n})`)) {
6526
+ n += 1;
6527
+ if (n > 999) return `${desired} (${n})`;
6528
+ }
6529
+ return `${desired} (${n})`;
6530
+ }
6531
+ function insertFolder(synced, folder, attachToTree) {
6532
+ const folders = { ...synced.collections.folders, [folder.id]: folder };
6533
+ const tree = attachToTree ? {
6534
+ ...synced.collections.tree,
6535
+ children: [...synced.collections.tree.children, { kind: "folder", id: folder.id }]
6536
+ } : synced.collections.tree;
6537
+ return {
6538
+ ...synced,
6539
+ collections: { ...synced.collections, folders, tree }
6540
+ };
6541
+ }
6542
+ function insertRequest(synced, request) {
6543
+ return {
6544
+ ...synced,
6545
+ collections: {
6546
+ ...synced.collections,
6547
+ requests: { ...synced.collections.requests, [request.id]: request }
6548
+ }
6549
+ };
6550
+ }
6551
+ function withGlobalAssets(synced) {
6552
+ return synced.globalAssets ?? { schemas: {}, graphql: {}, files: {} };
6553
+ }
6554
+ function findMatchingSchema(synced, candidate) {
6555
+ const ga = withGlobalAssets(synced);
6556
+ for (const existing of Object.values(ga.schemas)) {
6557
+ if (existing.name === candidate.name && existing.schema === candidate.schema) {
6558
+ return existing;
6559
+ }
6560
+ }
6561
+ return null;
6562
+ }
6563
+ function findMatchingGraphQL(synced, candidate) {
6564
+ const ga = withGlobalAssets(synced);
6565
+ for (const existing of Object.values(ga.graphql)) {
6566
+ if (existing.name === candidate.name && existing.kind === candidate.kind && existing.source === candidate.source) {
6567
+ return existing;
6568
+ }
6569
+ }
6570
+ return null;
6571
+ }
6572
+ function findMatchingFile(synced, candidate) {
6573
+ const ga = withGlobalAssets(synced);
6574
+ const files = ga.files ?? {};
6575
+ for (const existing of Object.values(files)) {
6576
+ if (existing.name === candidate.name && existing.filename === candidate.filename && existing.size === candidate.size) {
6577
+ return existing;
6578
+ }
6579
+ }
6580
+ return null;
6581
+ }
6582
+ function mergeGlobalSchema(synced, schema, now) {
6583
+ const ga = withGlobalAssets(synced);
6584
+ return {
6585
+ ...synced,
6586
+ globalAssets: {
6587
+ ...ga,
6588
+ schemas: { ...ga.schemas, [schema.id]: { ...schema, updatedAt: now } }
6589
+ }
6590
+ };
6591
+ }
6592
+ function mergeGlobalGraphQL(synced, graphql, now) {
6593
+ const ga = withGlobalAssets(synced);
6594
+ return {
6595
+ ...synced,
6596
+ globalAssets: {
6597
+ ...ga,
6598
+ graphql: { ...ga.graphql, [graphql.id]: { ...graphql, updatedAt: now } }
6599
+ }
6600
+ };
6601
+ }
6602
+ function mergeGlobalFile(synced, file, now) {
6603
+ const ga = withGlobalAssets(synced);
6604
+ const files = ga.files ?? {};
6605
+ return {
6606
+ ...synced,
6607
+ globalAssets: {
6608
+ ...ga,
6609
+ files: { ...files, [file.id]: { ...file, updatedAt: now } }
6610
+ }
6611
+ };
6612
+ }
6613
+ function rewriteRef(value, remap) {
6614
+ if (value === null || value === void 0) return value;
6615
+ return remap.get(value) ?? value;
6616
+ }
6617
+ function rewriteBodyFileRefs(body, remap) {
6618
+ if (body.type === "binary") {
6619
+ if (!body.attachment) return body;
6620
+ const rewritten = rewriteRef(body.attachment.globalFileAssetId, remap);
6621
+ if (rewritten === body.attachment.globalFileAssetId) return body;
6622
+ return {
6623
+ ...body,
6624
+ attachment: { ...body.attachment, globalFileAssetId: rewritten }
6625
+ };
6626
+ }
6627
+ if (body.type === "form-data" && body.formRows) {
6628
+ let mutated = false;
6629
+ const next = body.formRows.map((row) => {
6630
+ if (row.kind !== "file") return row;
6631
+ const rewritten = rewriteRef(row.globalFileAssetId, remap);
6632
+ if (rewritten === row.globalFileAssetId) return row;
6633
+ mutated = true;
6634
+ return { ...row, globalFileAssetId: rewritten };
6635
+ });
6636
+ return mutated ? { ...body, formRows: next } : body;
6637
+ }
6638
+ return body;
6639
+ }
6640
+
6641
+ // src/workspace/applyMutation.ts
5720
6642
  function applyMutation(state, patch, options = {}) {
5721
6643
  const now = options.now ?? (/* @__PURE__ */ new Date()).toISOString();
5722
6644
  switch (patch.kind) {
@@ -5732,6 +6654,8 @@ function applyMutation(state, patch, options = {}) {
5732
6654
  return applyFolderDelete(state, patch.id, now);
5733
6655
  case "folder.move":
5734
6656
  return applyFolderMove(state, patch.id, patch.newParentId, now);
6657
+ case "folder.import_apicircle":
6658
+ return applyFolderImportApicircle(state, patch.parsed, patch.parentFolderId, now);
5735
6659
  case "environment.upsert":
5736
6660
  return applyEnvUpsert(state, patch.environment, now);
5737
6661
  case "environment.delete":
@@ -5740,6 +6664,8 @@ function applyMutation(state, patch, options = {}) {
5740
6664
  return applyEnvSetActive(state, patch.name, now);
5741
6665
  case "environment.setPriority":
5742
6666
  return applyEnvSetPriority(state, patch.order, now);
6667
+ case "secretKey.upsert":
6668
+ return applySecretKeyUpsert(state, patch.meta, now);
5743
6669
  case "assertion.upsert":
5744
6670
  return applyAssertionUpsert(state, patch.requestId, patch.assertion, now);
5745
6671
  case "assertion.delete":
@@ -5900,6 +6826,23 @@ function applyFolderMove(state, id, newParentId, now) {
5900
6826
  };
5901
6827
  return { next: { ...state, synced }, changedIds: [id] };
5902
6828
  }
6829
+ function applyFolderImportApicircle(state, parsed, parentFolderId, now) {
6830
+ const result = importApicircleFolderInto(
6831
+ state.synced,
6832
+ parsed,
6833
+ parentFolderId
6834
+ );
6835
+ const synced = {
6836
+ ...result.synced,
6837
+ meta: { ...result.synced.meta, updatedAt: now }
6838
+ };
6839
+ const changedIds = [
6840
+ result.rootFolderId,
6841
+ ...parsed.subfolders.map((f) => f.id),
6842
+ ...parsed.requests.map((r) => r.id)
6843
+ ];
6844
+ return { next: { ...state, synced }, changedIds };
6845
+ }
5903
6846
  function applyEnvUpsert(state, environment, now) {
5904
6847
  const trimmed = environment.name.trim();
5905
6848
  if (!trimmed) {
@@ -5975,6 +6918,20 @@ function applyEnvSetPriority(state, order, now) {
5975
6918
  };
5976
6919
  return { next: { ...state, synced }, changedIds: filtered.map(envPriorityKey) };
5977
6920
  }
6921
+ function applySecretKeyUpsert(state, meta, now) {
6922
+ if (!meta.id || !meta.label.trim() || !meta.salt) {
6923
+ return { next: state, changedIds: [] };
6924
+ }
6925
+ const synced = {
6926
+ ...state.synced,
6927
+ secretKeys: {
6928
+ ...state.synced.secretKeys ?? {},
6929
+ [meta.id]: { ...meta, label: meta.label.trim() }
6930
+ },
6931
+ meta: { ...state.synced.meta, updatedAt: now }
6932
+ };
6933
+ return { next: { ...state, synced }, changedIds: [meta.id] };
6934
+ }
5978
6935
  function applyAssertionUpsert(state, requestId, assertion, now) {
5979
6936
  const request = state.synced.collections.requests[requestId];
5980
6937
  if (!request) {
@@ -6117,7 +7074,7 @@ function evictSnapshotsToCap(entries, maxBytes) {
6117
7074
  };
6118
7075
  }
6119
7076
  function applySnapshotCapture(state, args, now) {
6120
- const id = args.id ?? generateId();
7077
+ const id = args.id ?? generateId2();
6121
7078
  const snapshot2 = {
6122
7079
  id,
6123
7080
  createdAt: now,
@@ -6206,7 +7163,7 @@ function applyHistoryPurge(state, olderThanMs) {
6206
7163
  }
6207
7164
 
6208
7165
  // src/workspace/runPlan.ts
6209
- import { envPriorityKey as envPriorityKey2, generateId as generateId2, RUN_BODY_PREVIEW_LIMIT } from "@apicircle/shared";
7166
+ import { envPriorityKey as envPriorityKey2, generateId as generateId3, RUN_BODY_PREVIEW_LIMIT } from "@apicircle/shared";
6210
7167
  var MAX_REQUEST_RUNS = 500;
6211
7168
  var MAX_PLAN_RUNS = 200;
6212
7169
  var ANONYMOUS_ACTOR = { kind: "unknown", name: "unknown" };
@@ -6353,7 +7310,7 @@ async function runPlan(state, planId, opts = {}) {
6353
7310
  const baseRefs = plan.envPriorityOrder.length > 0 ? plan.envPriorityOrder : state.synced.environments.priorityOrder;
6354
7311
  const envRefs = opts.env ? [{ kind: "local", name: opts.env }, ...baseRefs] : baseRefs;
6355
7312
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
6356
- const planRunId = generateId2();
7313
+ const planRunId = generateId3();
6357
7314
  const t0 = Date.now();
6358
7315
  const stepRecords = [];
6359
7316
  const newRequestRuns = [];
@@ -6386,7 +7343,7 @@ async function runPlan(state, planId, opts = {}) {
6386
7343
  const lookup2 = lookupPlanStepRequest(step, state.synced, state.local);
6387
7344
  const baseRequest = lookup2.request;
6388
7345
  if (!baseRequest) {
6389
- const runId = generateId2();
7346
+ const runId = generateId3();
6390
7347
  const error = lookup2.error ?? "Request no longer exists in workspace.";
6391
7348
  newRequestRuns.push(orphanRun(runId, step.requestId, error));
6392
7349
  stepRecords.push({ requestRunId: runId, passed: false });
@@ -6618,7 +7575,7 @@ function orphanRun(id, requestId, error) {
6618
7575
  function buildRequestRun(resolved, result, assertions) {
6619
7576
  const { preview, truncated } = clampPreview(result.body ?? "");
6620
7577
  return {
6621
- id: generateId2(),
7578
+ id: generateId3(),
6622
7579
  requestId: resolved.id,
6623
7580
  startedAt: result.startedAt,
6624
7581
  durationMs: result.durationMs,
@@ -6924,6 +7881,7 @@ var TRANSFORM_FORMAT_LABELS = {
6924
7881
  };
6925
7882
  export {
6926
7883
  ANONYMOUS_ACTOR,
7884
+ APICIRCLE_FOLDER_EXPORT_FORMAT,
6927
7885
  DESKTOP_APP_ORIGIN,
6928
7886
  EMPTY_UNPUSHED_SUMMARY,
6929
7887
  HTTP_HEADERS_MAP,
@@ -6948,6 +7906,8 @@ export {
6948
7906
  buildRequest,
6949
7907
  buildScope,
6950
7908
  collectAttachmentSlots,
7909
+ collectFolderExport,
7910
+ collectFolderExportCredentials,
6951
7911
  collectVariableSuggestions,
6952
7912
  compareSemver,
6953
7913
  composeBody,
@@ -6983,7 +7943,10 @@ export {
6983
7943
  getLanguageFromContentType,
6984
7944
  getVariableAutocomplete,
6985
7945
  hasUnpushedChanges,
7946
+ importApicircleFolderInto,
6986
7947
  importKey,
7948
+ isApicircleEnvironment,
7949
+ isApicircleFolderExport,
6987
7950
  isDesktop,
6988
7951
  isInsomniaExport,
6989
7952
  isPostmanEnvironment,
@@ -6992,6 +7955,10 @@ export {
6992
7955
  lookup,
6993
7956
  mergeWithAutoHeaders,
6994
7957
  normalizeContentType,
7958
+ parseApicircleEnvironment,
7959
+ parseApicircleEnvironmentDoc,
7960
+ parseApicircleFolderExport,
7961
+ parseApicircleFolderExportDoc,
6995
7962
  parseCurl,
6996
7963
  parseDigestChallenge,
6997
7964
  parseGraphqlSchema,
@@ -7007,6 +7974,7 @@ export {
7007
7974
  previewLinkedUpdate,
7008
7975
  publishRelease,
7009
7976
  readJsonPath,
7977
+ redactFolderExportCredentials,
7010
7978
  redactForGit,
7011
7979
  refreshToken,
7012
7980
  requestDeviceAuthorization,
@@ -7019,11 +7987,13 @@ export {
7019
7987
  runClientCredentials,
7020
7988
  runPlan,
7021
7989
  runRopc,
7990
+ serializeFolderExport,
7022
7991
  serializePayload,
7023
7992
  serializeWorkspaceForGit,
7024
7993
  signJwt,
7025
7994
  slugify,
7026
7995
  sortVersionsDesc,
7996
+ suggestFolderExportFilename,
7027
7997
  suggestHeaders,
7028
7998
  summarizeUnpushedChanges,
7029
7999
  supportedContentTypeLanguageMap,