@apicircle/shared 1.0.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/dist/index.js ADDED
@@ -0,0 +1,487 @@
1
+ // src/ids.ts
2
+ function generateId() {
3
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
4
+ return crypto.randomUUID();
5
+ }
6
+ const bytes = new Uint8Array(16);
7
+ if (typeof crypto !== "undefined") {
8
+ crypto.getRandomValues(bytes);
9
+ } else {
10
+ for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256);
11
+ }
12
+ bytes[6] = bytes[6] & 15 | 64;
13
+ bytes[8] = bytes[8] & 63 | 128;
14
+ const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
15
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
16
+ }
17
+
18
+ // src/validators.ts
19
+ var OK = { ok: true };
20
+ var fail = (reason) => ({ ok: false, reason });
21
+ function validateUrl(value) {
22
+ const trimmed = value.trim();
23
+ if (!trimmed) return fail("URL is required.");
24
+ if (/^\s*\{\{\s*[^{}]+\s*\}\}/.test(trimmed)) return OK;
25
+ const probe = trimmed.replace(/\{\{[^{}]+\}\}/g, "placeholder");
26
+ try {
27
+ const u = new URL(probe);
28
+ if (!/^https?:|^file:$/i.test(u.protocol)) {
29
+ return fail(`Unsupported scheme "${u.protocol}". Use http(s):// or file://.`);
30
+ }
31
+ if (u.protocol !== "file:" && !u.host) return fail("URL is missing a host.");
32
+ return OK;
33
+ } catch {
34
+ return fail("Not a valid URL. Expected http(s)://host/path.");
35
+ }
36
+ }
37
+ var AWS_DIRECTIONS = /* @__PURE__ */ new Set([
38
+ "east",
39
+ "west",
40
+ "north",
41
+ "south",
42
+ "central",
43
+ "northeast",
44
+ "northwest",
45
+ "southeast",
46
+ "southwest"
47
+ ]);
48
+ function validateAwsRegion(value) {
49
+ const v = value.trim().toLowerCase();
50
+ if (!v) return fail("Region is required (e.g. us-east-1).");
51
+ const m = /^([a-z]{2,3})-(?:([a-z]+)-)?([a-z]+)-(\d+)$/.exec(v);
52
+ if (!m) return fail('Region must look like "us-east-1" or "us-gov-west-1".');
53
+ const direction = m[3];
54
+ if (!AWS_DIRECTIONS.has(direction)) {
55
+ return fail(`Unknown direction "${direction}". Expected east/west/north/south/central/etc.`);
56
+ }
57
+ return OK;
58
+ }
59
+ function validateMockPath(value) {
60
+ const v = value.trim();
61
+ if (!v) return fail("Path is required.");
62
+ if (!v.startsWith("/")) return fail('Path must start with "/".');
63
+ if (/\s/.test(v)) return fail("Path must not contain whitespace.");
64
+ if (v.includes("?")) return fail("Path must not include a query string.");
65
+ if (v.includes("#")) return fail("Path must not include a fragment.");
66
+ return OK;
67
+ }
68
+ function validateEnvVarName(value) {
69
+ const v = value.trim();
70
+ if (!v) return fail("Variable name is required.");
71
+ if (/[\s{}]/.test(v)) return fail("Variable name cannot contain spaces or braces.");
72
+ if (!/^[A-Za-z_][A-Za-z0-9_-]*$/.test(v)) {
73
+ return fail("Use letters, digits, underscores, hyphens. Must start with a letter or _.");
74
+ }
75
+ return OK;
76
+ }
77
+ function validatePlanName(value) {
78
+ const v = value.trim();
79
+ if (!v) return fail("Plan name is required.");
80
+ if (v.length > 80) return fail("Plan name must be 80 characters or fewer.");
81
+ return OK;
82
+ }
83
+ function validatePRTitle(value) {
84
+ const v = value.trim();
85
+ if (!v) return fail("Title is required.");
86
+ if (v.length > 256) return fail("Title must be 256 characters or fewer.");
87
+ return OK;
88
+ }
89
+ function validateJsonString(value, opts = {}) {
90
+ const v = value.trim();
91
+ if (!v) {
92
+ if (opts.allowEmpty) return OK;
93
+ return fail("JSON cannot be empty.");
94
+ }
95
+ let parsed;
96
+ try {
97
+ parsed = JSON.parse(v);
98
+ } catch (e) {
99
+ return fail(`Invalid JSON: ${e instanceof Error ? e.message : "parse failed"}.`);
100
+ }
101
+ const allow = opts.allowRoots ?? "any";
102
+ if (allow === "object" && (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))) {
103
+ return fail("JSON root must be an object.");
104
+ }
105
+ if (allow === "array" && !Array.isArray(parsed)) {
106
+ return fail("JSON root must be an array.");
107
+ }
108
+ return OK;
109
+ }
110
+ var HEADER_TOKEN_RE = /^[A-Za-z0-9!#$%&'*+\-.^_`|~]+$/;
111
+ function validateHttpHeaderName(value) {
112
+ const v = value.trim();
113
+ if (!v) return fail("Header name is required.");
114
+ if (!HEADER_TOKEN_RE.test(v)) {
115
+ return fail("Header name must be a valid HTTP token (letters, digits, and -_.!#$%&'*+^`|~).");
116
+ }
117
+ return OK;
118
+ }
119
+ function validateRegex(value, flags) {
120
+ if (value === "") return fail("Regex cannot be empty.");
121
+ try {
122
+ new RegExp(value, flags);
123
+ return OK;
124
+ } catch (e) {
125
+ return fail(`Invalid regex: ${e instanceof Error ? e.message : "parse failed"}.`);
126
+ }
127
+ }
128
+ var JSON_PATH_RE = /^\$(\.\.?[A-Za-z_$][\w$]*|\[(?:\*|\d+|'[^']*')\])*$/;
129
+ function validateJsonPath(value) {
130
+ const v = value.trim();
131
+ if (!v) return fail("JSONPath cannot be empty.");
132
+ if (!v.startsWith("$")) return fail('JSONPath must start with "$".');
133
+ if (!JSON_PATH_RE.test(v)) {
134
+ return fail("JSONPath syntax looks malformed \u2014 expected $.foo.bar or $.items[0].name.");
135
+ }
136
+ return OK;
137
+ }
138
+ function validatePositiveDuration(value) {
139
+ const n = typeof value === "string" ? Number(value) : value;
140
+ if (!Number.isFinite(n)) return fail("Duration must be a number.");
141
+ if (n < 0) return fail("Duration cannot be negative.");
142
+ if (!Number.isInteger(n)) return fail("Duration must be a whole number.");
143
+ return OK;
144
+ }
145
+ function safeExternalHref(value) {
146
+ if (typeof value !== "string" || value.length === 0) return null;
147
+ let parsed;
148
+ try {
149
+ parsed = new URL(value);
150
+ } catch {
151
+ return null;
152
+ }
153
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return null;
154
+ return parsed.toString();
155
+ }
156
+
157
+ // src/format.ts
158
+ function formatBytes(bytes) {
159
+ if (!Number.isFinite(bytes) || bytes < 0) return "\u2014";
160
+ if (bytes < 1024) return `${bytes} B`;
161
+ const units = ["KB", "MB", "GB", "TB"];
162
+ let value = bytes / 1024;
163
+ let unitIdx = 0;
164
+ while (value >= 1024 && unitIdx < units.length - 1) {
165
+ value /= 1024;
166
+ unitIdx++;
167
+ }
168
+ return `${value.toFixed(value >= 100 ? 0 : value >= 10 ? 1 : 2)} ${units[unitIdx]}`;
169
+ }
170
+ function utf8ByteLength(s) {
171
+ if (typeof TextEncoder === "undefined") return s.length;
172
+ return new TextEncoder().encode(s).length;
173
+ }
174
+
175
+ // src/envPriority.ts
176
+ function envPriorityKey(ref) {
177
+ if (ref.kind === "local") return `local:${ref.name}`;
178
+ return `linked:${ref.linkedWorkspaceId}:${ref.envName}`;
179
+ }
180
+ function parseEnvPriorityKey(key) {
181
+ if (key.startsWith("local:")) {
182
+ return { kind: "local", name: key.slice("local:".length) };
183
+ }
184
+ if (key.startsWith("linked:")) {
185
+ const rest = key.slice("linked:".length);
186
+ const colonIdx = rest.indexOf(":");
187
+ if (colonIdx === -1) return null;
188
+ return {
189
+ kind: "linked",
190
+ linkedWorkspaceId: rest.slice(0, colonIdx),
191
+ envName: rest.slice(colonIdx + 1)
192
+ };
193
+ }
194
+ return null;
195
+ }
196
+ function envPriorityRefEqual(a, b) {
197
+ if (a.kind !== b.kind) return false;
198
+ if (a.kind === "local") return b.kind === "local" && a.name === b.name;
199
+ return b.kind === "linked" && a.linkedWorkspaceId === b.linkedWorkspaceId && a.envName === b.envName;
200
+ }
201
+ function envPriorityDisplayName(ref) {
202
+ return ref.kind === "local" ? ref.name : ref.envName;
203
+ }
204
+
205
+ // src/types.ts
206
+ var DEFAULT_WORKSPACE_NAME = "My Workspace";
207
+ var RUN_BODY_PREVIEW_LIMIT = 64 * 1024;
208
+ var FONT_SIZE_PERCENT_MIN = 80;
209
+ var FONT_SIZE_PERCENT_MAX = 150;
210
+ var FONT_SIZE_PERCENT_STEP = 10;
211
+ var FONT_SIZE_PERCENT_DEFAULT = 100;
212
+
213
+ // src/authDefaults.ts
214
+ var oauth2TokenDefaults = {
215
+ accessToken: "",
216
+ tokenType: "Bearer",
217
+ refreshToken: "",
218
+ expiresAt: null,
219
+ obtainedScope: ""
220
+ };
221
+ var FACTORIES = {
222
+ none: () => ({ type: "none" }),
223
+ inherit: () => ({ type: "inherit" }),
224
+ bearer: () => ({ type: "bearer", token: "" }),
225
+ basic: () => ({ type: "basic", username: "", password: "" }),
226
+ "api-key": () => ({ type: "api-key", key: "", value: "", addTo: "header" }),
227
+ "custom-header": () => ({ type: "custom-header", key: "", value: "" }),
228
+ "oauth2-client-credentials": () => ({
229
+ type: "oauth2-client-credentials",
230
+ tokenUrl: "",
231
+ clientId: "",
232
+ clientSecret: "",
233
+ scope: "",
234
+ clientAuthMethod: "header",
235
+ ...oauth2TokenDefaults
236
+ }),
237
+ "oauth2-auth-code": () => ({
238
+ type: "oauth2-auth-code",
239
+ authUrl: "",
240
+ tokenUrl: "",
241
+ clientId: "",
242
+ clientSecret: "",
243
+ redirectUri: "",
244
+ scope: "",
245
+ state: "",
246
+ ...oauth2TokenDefaults
247
+ }),
248
+ "oauth2-pkce": () => ({
249
+ type: "oauth2-pkce",
250
+ authUrl: "",
251
+ tokenUrl: "",
252
+ clientId: "",
253
+ clientSecret: "",
254
+ redirectUri: "",
255
+ scope: "",
256
+ state: "",
257
+ codeVerifier: "",
258
+ codeChallengeMethod: "S256",
259
+ ...oauth2TokenDefaults
260
+ }),
261
+ "oauth2-password": () => ({
262
+ type: "oauth2-password",
263
+ tokenUrl: "",
264
+ clientId: "",
265
+ clientSecret: "",
266
+ username: "",
267
+ password: "",
268
+ scope: "",
269
+ ...oauth2TokenDefaults
270
+ }),
271
+ "oauth2-implicit": () => ({
272
+ type: "oauth2-implicit",
273
+ authUrl: "",
274
+ clientId: "",
275
+ redirectUri: "",
276
+ scope: "",
277
+ accessToken: "",
278
+ tokenType: "Bearer",
279
+ expiresAt: null,
280
+ obtainedScope: ""
281
+ }),
282
+ "oauth2-device": () => ({
283
+ type: "oauth2-device",
284
+ deviceAuthUrl: "",
285
+ tokenUrl: "",
286
+ clientId: "",
287
+ scope: "",
288
+ deviceCode: "",
289
+ userCode: "",
290
+ verificationUri: "",
291
+ ...oauth2TokenDefaults
292
+ }),
293
+ "aws-sigv4": () => ({
294
+ type: "aws-sigv4",
295
+ accessKeyId: "",
296
+ secretAccessKey: "",
297
+ sessionToken: "",
298
+ region: "us-east-1",
299
+ service: "",
300
+ addTo: "header"
301
+ }),
302
+ digest: () => ({ type: "digest", username: "", password: "" }),
303
+ ntlm: () => ({
304
+ type: "ntlm",
305
+ username: "",
306
+ password: "",
307
+ domain: "",
308
+ workstation: ""
309
+ }),
310
+ hawk: () => ({
311
+ type: "hawk",
312
+ hawkId: "",
313
+ hawkKey: "",
314
+ algorithm: "sha256",
315
+ ext: ""
316
+ }),
317
+ "jwt-bearer": () => ({
318
+ type: "jwt-bearer",
319
+ algorithm: "HS256",
320
+ secretOrKey: "",
321
+ payload: '{\n "sub": "user-id",\n "iat": 1700000000\n}',
322
+ jwtHeaders: '{\n "typ": "JWT"\n}',
323
+ token: ""
324
+ })
325
+ };
326
+ function defaultAuthFor(type) {
327
+ return FACTORIES[type]();
328
+ }
329
+ function normalizeAuth(input) {
330
+ if (input && typeof input === "object" && "type" in input && typeof input.type === "string" && input.type in FACTORIES) {
331
+ return input;
332
+ }
333
+ return { type: "none" };
334
+ }
335
+ var REQUEST_AUTH_TYPES = Object.keys(
336
+ FACTORIES
337
+ );
338
+
339
+ // src/mcp.ts
340
+ var MCP_TOOL_NAMES = [
341
+ "import.curl",
342
+ "import.openapi",
343
+ "import.postman",
344
+ "import.insomnia",
345
+ "import.har",
346
+ "generate.code",
347
+ "workspace.read",
348
+ "workspace.write",
349
+ "request.create",
350
+ "request.read",
351
+ "request.update",
352
+ "request.delete",
353
+ "folder.create",
354
+ "folder.read",
355
+ "folder.update",
356
+ "folder.delete",
357
+ "environment.create",
358
+ "environment.read",
359
+ "environment.update",
360
+ "environment.delete",
361
+ "environment.set_active",
362
+ "environment.set_priority",
363
+ "environment.export",
364
+ "environment.import",
365
+ "plan.create",
366
+ "plan.run",
367
+ "plan.read",
368
+ "plan.update",
369
+ "plan.delete",
370
+ "plan.add_step",
371
+ "plan.remove_step",
372
+ "plan.reorder_steps",
373
+ "plan.set_variables",
374
+ "assertion.create",
375
+ "assertion.read",
376
+ "assertion.update",
377
+ "assertion.delete",
378
+ "history.list_runs",
379
+ "history.get_run",
380
+ "history.delete_run",
381
+ "history.purge_by_age",
382
+ "codebase.extract_collection",
383
+ "prompt.create_environment",
384
+ "prompt.create_assertion",
385
+ "prompt.create_plan",
386
+ "prompt.create_request",
387
+ "prompt.update_request",
388
+ "prompt.create_folder_tree",
389
+ "prompt.add_plan_steps",
390
+ "prompt.set_plan_variables",
391
+ "prompt.create_mock_server",
392
+ "prompt.add_mock_endpoint",
393
+ "prompt.set_endpoint_validation_rules",
394
+ "prompt.set_endpoint_response_rules",
395
+ "prompt.set_endpoint_multipliers",
396
+ "mock.create_from_openapi",
397
+ "mock.create_from_postman",
398
+ "mock.create_from_insomnia",
399
+ "mock.create_manual",
400
+ "mock.list",
401
+ "mock.list_endpoints",
402
+ "mock.start",
403
+ "mock.stop",
404
+ "mock.delete",
405
+ "mock.add_endpoint",
406
+ "mock.update_endpoint",
407
+ "mock.delete_endpoint",
408
+ "mock.set_validation_rules",
409
+ "mock.set_response_rules",
410
+ "mock.set_multipliers",
411
+ "mock.import_postman_mock_collection"
412
+ ];
413
+
414
+ // src/mock.ts
415
+ var NO_BODY_STATUSES = /* @__PURE__ */ new Set([100, 101, 102, 103, 204, 205, 304]);
416
+ function getAllowedMockResponseBodyTypes(status) {
417
+ if (NO_BODY_STATUSES.has(status)) return ["none"];
418
+ if (status === 200) {
419
+ return ["none", "json", "text", "xml", "urlencoded", "form-data", "binary"];
420
+ }
421
+ return ["none", "json", "text", "xml", "urlencoded", "form-data"];
422
+ }
423
+ function coerceMockResponseBodyTypeForStatus(currentBodyType, status) {
424
+ const allowed = getAllowedMockResponseBodyTypes(status);
425
+ if (allowed.includes(currentBodyType)) return null;
426
+ if (allowed.includes("json")) return "json";
427
+ return "none";
428
+ }
429
+ function makeDefaultMockResponseBody(type) {
430
+ switch (type) {
431
+ case "none":
432
+ return { type: "none", content: "" };
433
+ case "form-data":
434
+ return { type: "form-data", content: "", formRows: [] };
435
+ case "binary":
436
+ return { type: "binary", content: "" };
437
+ default:
438
+ return { type, content: "" };
439
+ }
440
+ }
441
+ function makeDefaultMockResponse() {
442
+ return {
443
+ status: 200,
444
+ headers: [{ key: "Content-Type", value: "application/json", enabled: true }],
445
+ body: { type: "json", content: '{\n "ok": true\n}' }
446
+ };
447
+ }
448
+ function makeDefaultRequestSchema() {
449
+ return { pathParams: [], queryParams: [], headers: [], cookies: [] };
450
+ }
451
+ export {
452
+ DEFAULT_WORKSPACE_NAME,
453
+ FONT_SIZE_PERCENT_DEFAULT,
454
+ FONT_SIZE_PERCENT_MAX,
455
+ FONT_SIZE_PERCENT_MIN,
456
+ FONT_SIZE_PERCENT_STEP,
457
+ MCP_TOOL_NAMES,
458
+ REQUEST_AUTH_TYPES,
459
+ RUN_BODY_PREVIEW_LIMIT,
460
+ coerceMockResponseBodyTypeForStatus,
461
+ defaultAuthFor,
462
+ envPriorityDisplayName,
463
+ envPriorityKey,
464
+ envPriorityRefEqual,
465
+ formatBytes,
466
+ generateId,
467
+ getAllowedMockResponseBodyTypes,
468
+ makeDefaultMockResponse,
469
+ makeDefaultMockResponseBody,
470
+ makeDefaultRequestSchema,
471
+ normalizeAuth,
472
+ parseEnvPriorityKey,
473
+ safeExternalHref,
474
+ utf8ByteLength,
475
+ validateAwsRegion,
476
+ validateEnvVarName,
477
+ validateHttpHeaderName,
478
+ validateJsonPath,
479
+ validateJsonString,
480
+ validateMockPath,
481
+ validatePRTitle,
482
+ validatePlanName,
483
+ validatePositiveDuration,
484
+ validateRegex,
485
+ validateUrl
486
+ };
487
+ //# sourceMappingURL=index.js.map