@apicircle/shared 1.0.8 → 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/dist/index.d.cts CHANGED
@@ -132,15 +132,26 @@ interface MockResponseConfig {
132
132
  delayMs?: number;
133
133
  /**
134
134
  * Optional response-shape multipliers. At runtime, each multiplier reads a
135
- * value from the request (a query/path/header param or a JSON-path slice
136
- * of the request body) and repeats the array element at `targetJsonPath`
137
- * inside the response body that many times. Used to drive page-size
138
- * aware mock responses without templating the body manually.
135
+ * value from the request (a query/path/header param or a JSON-path slice of
136
+ * the request body) and repeats the array element at `targetJsonPath` inside
137
+ * the response body that many times. Used to drive page-size aware mock
138
+ * responses without templating the body manually.
139
139
  *
140
- * Only fires when `body.type === 'json'`; ignored otherwise.
140
+ * The persisted shape is an array so the feature can grow to N multipliers
141
+ * without a schema migration. For now the authoring surfaces (editors, MCP
142
+ * tools) cap the list at {@link MAX_RESPONSE_MULTIPLIERS}; the runtime applies
143
+ * every entry it finds (so a future cap bump — or a hand-edit — needs no
144
+ * engine change). Only fires when `body.type === 'json'`; ignored otherwise.
141
145
  */
142
146
  multipliers?: MockResponseMultiplier[];
143
147
  }
148
+ /**
149
+ * How many response multipliers the authoring surfaces (desktop/web editor,
150
+ * VS Code lenses, MCP tools) allow per response. The persisted shape is an
151
+ * array, so raising this to N — or removing the gate — is the ONLY change
152
+ * needed to support multiple multipliers; no data migration, no engine change.
153
+ */
154
+ declare const MAX_RESPONSE_MULTIPLIERS = 1;
144
155
  type MockMultiplierSourceKind = 'query' | 'pathParam' | 'header' | 'body-json-path';
145
156
  interface MockMultiplierSource {
146
157
  kind: MockMultiplierSourceKind;
@@ -227,6 +238,14 @@ interface MockResponseRule {
227
238
  when: MockConditionClause[];
228
239
  response: MockResponseConfig;
229
240
  }
241
+ /**
242
+ * How many `when` clauses the authoring surfaces (VS Code lenses, desktop/web
243
+ * editor, MCP tools) allow per response rule. The persisted shape is an array
244
+ * and the runtime AND-combines every clause it finds, so raising this to N — or
245
+ * removing the gate — is the ONLY change needed to support multi-clause rules;
246
+ * no data migration, no engine change. Mirrors {@link MAX_RESPONSE_MULTIPLIERS}.
247
+ */
248
+ declare const MAX_RESPONSE_RULE_CONDITIONS = 1;
230
249
  interface MockEndpoint {
231
250
  /** Stable id; survives spec re-parses so per-endpoint overrides keep matching. */
232
251
  id: string;
@@ -486,6 +505,38 @@ interface GlobalGraphQL {
486
505
  createdAt: string;
487
506
  updatedAt: string;
488
507
  }
508
+ /**
509
+ * Pointer to a verified-good copy of a Global File Asset's bytes on a
510
+ * specific Git ref. Each asset can carry up to two of these — one for
511
+ * the consumer's working branch and one for the base branch the working
512
+ * branch was forked from — and the cleanup invariant drops the working
513
+ * ref once the base ref holds the same blob (single source of truth).
514
+ *
515
+ * Populated lazily — never at upload time. The first push promotes the
516
+ * pending upload to `workingBranchRef`; the next refresh after the PR
517
+ * merges promotes to `baseBranchRef`. See
518
+ * docs/architecture/platform.md for the full state machine.
519
+ */
520
+ interface AssetGitRef {
521
+ /** Branch the asset is known to live on. */
522
+ branchName: string;
523
+ /**
524
+ * GitHub blob SHA at the most recent successful verification. Drives
525
+ * the cleanup invariant — when both refs return the same `blobSha` the
526
+ * working ref is redundant and gets dropped. Optional because legacy
527
+ * entries persisted before this field existed; consumers treat absent
528
+ * as "not yet verified."
529
+ */
530
+ blobSha?: string;
531
+ /**
532
+ * Commit SHA the ref was first recorded at. Used for display
533
+ * ("On main · since v2.3.1") and for the "branch retargeted" detection
534
+ * path where the same branchName resolves to a different blob.
535
+ */
536
+ commitSha?: string;
537
+ /** ISO timestamp of the last successful read of this ref. */
538
+ verifiedAt: string;
539
+ }
489
540
  interface GlobalFileAsset {
490
541
  id: string;
491
542
  name: string;
@@ -497,6 +548,55 @@ interface GlobalFileAsset {
497
548
  sha256?: string;
498
549
  createdAt: string;
499
550
  updatedAt: string;
551
+ /**
552
+ * Provenance pointer to the asset's bytes on the consumer's currently
553
+ * connected working branch. Set by the push flow after `updateRef`
554
+ * resolves with the GitHub blob sha. Dropped by the cleanup invariant
555
+ * when `baseBranchRef` holds the same blob. Optional — pre-1.0.9 docs
556
+ * and freshly-uploaded-but-unpushed assets leave it `undefined`.
557
+ */
558
+ workingBranchRef?: AssetGitRef | null;
559
+ /**
560
+ * Provenance pointer to the asset's bytes on the base branch the
561
+ * working branch was forked from (usually `main`). Set by the refresh
562
+ * verification probe once the PR merges. Optional — assets that have
563
+ * never been merged leave it `undefined`.
564
+ */
565
+ baseBranchRef?: AssetGitRef | null;
566
+ }
567
+ /**
568
+ * Local-only buffer recording an asset whose bytes are in IDB but have
569
+ * not yet been pushed to any Git ref. Keyed by `globalFileAssetId` so
570
+ * the desktop / web can render an "Uploaded locally" state pill and the
571
+ * push flow knows which slots still need to be uploaded as blobs. Dropped
572
+ * by the push flow after `globalAsset.markPushed` lands.
573
+ */
574
+ interface PendingFileUpload {
575
+ slotId: string;
576
+ filename: string;
577
+ mimeType: string;
578
+ sha256: string;
579
+ size: number;
580
+ /** ISO timestamp the file was dropped into the studio. */
581
+ queuedAt: string;
582
+ }
583
+ /**
584
+ * Where a Global File Asset is referenced inside the current synced doc.
585
+ * Recomputed by `assetUsageAggregator` after every `commitSynced`. Used
586
+ * to surface "Used in N places" in the Global Assets panel, the form-data
587
+ * row, the binary body, and the mock-response editors, and to flag
588
+ * zero-use orphans for one-click cleanup.
589
+ */
590
+ interface AssetUsage {
591
+ /** Request ids whose body binds this asset. */
592
+ requests: string[];
593
+ /** Mock endpoints whose responses bind this asset. */
594
+ mockEndpoints: Array<{
595
+ mockId: string;
596
+ endpointId: string;
597
+ }>;
598
+ /** Total reference count — denormalised for cheap badge rendering. */
599
+ total: number;
500
600
  }
501
601
  type RequestAuth = {
502
602
  type: 'none';
@@ -677,7 +777,7 @@ interface LocalAttachmentCacheEntry {
677
777
  /**
678
778
  * Local-only path or storage URI where this device can read the bytes for
679
779
  * execution. Browser builds use an IndexedDB URI; CLI runs use an absolute
680
- * filesystem path under `.apicircle/attachments/`.
780
+ * filesystem path under `.apicircle/workspace-<id>/attachments/`.
681
781
  */
682
782
  localPath: string;
683
783
  storage: 'indexeddb' | 'filesystem';
@@ -754,6 +854,10 @@ interface LinkedWorkspace {
754
854
  kind: 'private' | 'public';
755
855
  name: string;
756
856
  description?: string;
857
+ /** The remote workspace's `workspaceId` (from the source's registry).
858
+ * Needed to resolve per-workspace paths (attachments, workspace.json)
859
+ * when fetching from the source repo. */
860
+ sourceWorkspaceId: string;
757
861
  source: {
758
862
  provider: 'github';
759
863
  repoFullName: string;
@@ -900,6 +1004,39 @@ interface WorkspaceLocal {
900
1004
  * eviction.
901
1005
  */
902
1006
  snapshots: WorkspaceSnapshotLedger;
1007
+ /**
1008
+ * Pre-push buffer for Global File Asset bytes. Each entry mirrors the
1009
+ * IDB attachment record (which stays the authoritative byte store) but
1010
+ * is keyed by `globalFileAssetId` instead of `slotId`, making it easy
1011
+ * for the push flow + the status-pill UI to ask "is this asset still
1012
+ * pending upload?" without scanning IDB. Dropped per-asset after the
1013
+ * push promotes the asset to `workingBranchRef`.
1014
+ */
1015
+ pendingFileUploads?: Record<string, PendingFileUpload>;
1016
+ /**
1017
+ * Cross-cutting reference index for Global File Assets. Recomputed by
1018
+ * `assetUsageAggregator` whenever `commitSynced` runs, mirroring the
1019
+ * `secretIndex.entries[].usedIn` pattern. Local-only because it's pure
1020
+ * cache — the truth lives in `synced.collections.requests` and
1021
+ * `synced.mockServers`.
1022
+ */
1023
+ assetUsageIndex?: Record<string, AssetUsage>;
1024
+ /**
1025
+ * Slot ids whose attachment blob needs to be DELETED from the working
1026
+ * branch on the next push. Queued by `removeGlobalFileAsset` (and the
1027
+ * headless `globalAsset.removeFile` patch) when the asset being
1028
+ * deleted had any push provenance (`workingBranchRef` or
1029
+ * `baseBranchRef`). The push emits
1030
+ * `{path: '.apicircle/workspace-<id>/attachments/<slotId>', sha: null}`
1031
+ * tree entries layered over `base_tree`, which GitHub treats as
1032
+ * deletions. After a successful push, the queue is cleared — the
1033
+ * deletion is durable on the working branch, and the eventual PR
1034
+ * merge propagates it to the base branch.
1035
+ *
1036
+ * Without this queue, the asset would be removed from `workspace.json`
1037
+ * but the orphan blob would persist on the remote tree forever.
1038
+ */
1039
+ pendingAttachmentDeletes?: string[];
903
1040
  }
904
1041
  interface WorkspaceLocalSettings {
905
1042
  validateOnSend: boolean;
@@ -1283,7 +1420,7 @@ declare const REQUEST_AUTH_TYPES: ReadonlyArray<RequestAuthType>;
1283
1420
  * clients can group them in their UI. Keep in sync with the registry in
1284
1421
  * `packages/mcp-server/src/tools/registry.ts`.
1285
1422
  */
1286
- type McpToolName = 'import.curl' | 'import.openapi' | 'import.postman' | 'import.insomnia' | 'import.har' | 'generate.code' | 'workspace.list' | 'workspace.read' | 'workspace.write' | 'request.create' | 'request.read' | 'request.update' | 'request.delete' | 'folder.create' | 'folder.read' | 'folder.update' | 'folder.delete' | 'folder.export_json' | 'folder.import_json' | 'environment.create' | 'environment.read' | 'environment.update' | 'environment.delete' | 'environment.set_active' | 'environment.set_priority' | 'environment.export' | 'environment.import' | 'plan.create' | 'plan.run' | 'plan.read' | 'plan.update' | 'plan.delete' | 'plan.add_step' | 'plan.remove_step' | 'plan.reorder_steps' | 'plan.set_variables' | 'assertion.create' | 'assertion.read' | 'assertion.update' | 'assertion.delete' | 'history.list_runs' | 'history.get_run' | 'history.delete_run' | 'history.purge_by_age' | 'codebase.extract_collection' | 'prompt.create_environment' | 'prompt.create_assertion' | 'prompt.create_plan' | 'prompt.create_request' | 'prompt.update_request' | 'prompt.create_folder_tree' | 'prompt.add_plan_steps' | 'prompt.set_plan_variables' | 'prompt.create_mock_server' | 'prompt.add_mock_endpoint' | 'prompt.set_endpoint_validation_rules' | 'prompt.set_endpoint_response_rules' | 'prompt.set_endpoint_multipliers' | 'mock.create_from_openapi' | 'mock.create_from_postman' | 'mock.create_from_insomnia' | 'mock.create_manual' | 'mock.list' | 'mock.list_endpoints' | 'mock.start' | 'mock.stop' | 'mock.delete' | 'mock.add_endpoint' | 'mock.update_endpoint' | 'mock.delete_endpoint' | 'mock.set_validation_rules' | 'mock.set_response_rules' | 'mock.set_multipliers' | 'mock.import_postman_mock_collection';
1423
+ type McpToolName = 'import.curl' | 'import.openapi' | 'import.postman' | 'import.insomnia' | 'import.har' | 'generate.code' | 'workspace.list' | 'workspace.read' | 'workspace.write' | 'request.create' | 'request.read' | 'request.update' | 'request.delete' | 'folder.create' | 'folder.read' | 'folder.update' | 'folder.delete' | 'folder.export_json' | 'folder.import_json' | 'environment.create' | 'environment.read' | 'environment.update' | 'environment.delete' | 'environment.set_active' | 'environment.set_priority' | 'environment.export' | 'environment.import' | 'plan.create' | 'plan.run' | 'plan.read' | 'plan.update' | 'plan.delete' | 'plan.add_step' | 'plan.remove_step' | 'plan.reorder_steps' | 'plan.set_variables' | 'assertion.create' | 'assertion.read' | 'assertion.update' | 'assertion.delete' | 'history.list_runs' | 'history.get_run' | 'history.delete_run' | 'history.purge_by_age' | 'codebase.extract_collection' | 'prompt.create_environment' | 'prompt.create_assertion' | 'prompt.create_plan' | 'prompt.create_request' | 'prompt.update_request' | 'prompt.create_folder_tree' | 'prompt.add_plan_steps' | 'prompt.set_plan_variables' | 'prompt.create_mock_server' | 'prompt.add_mock_endpoint' | 'prompt.set_endpoint_validation_rules' | 'prompt.set_endpoint_response_rules' | 'prompt.set_endpoint_multipliers' | 'prompt.set_endpoint_request_schema' | 'assets.list_files' | 'assets.create_file' | 'assets.update_file' | 'assets.delete_file' | 'mock.create_from_openapi' | 'mock.create_from_postman' | 'mock.create_from_insomnia' | 'mock.create_manual' | 'mock.list' | 'mock.list_endpoints' | 'mock.start' | 'mock.stop' | 'mock.delete' | 'mock.add_endpoint' | 'mock.update_endpoint' | 'mock.delete_endpoint' | 'mock.set_validation_rules' | 'mock.set_response_rules' | 'mock.set_multipliers' | 'mock.set_request_schema' | 'mock.set_default_port' | 'mock.import_postman_mock_collection' | 'release.list' | 'release.publish' | 'release.deprecate' | 'release.yank' | 'linked.list' | 'linked.get' | 'linked.set_config' | 'linked.unlink' | 'linked.link' | 'linked.refresh' | 'release.tag' | 'repo.set_topics' | 'marketplace.search';
1287
1424
  interface McpError {
1288
1425
  code: 'invalid_input' | 'not_found' | 'conflict' | 'unsupported' | 'internal';
1289
1426
  message: string;
@@ -1292,4 +1429,4 @@ interface McpError {
1292
1429
  /** Helper: full enumeration of tool names — useful for the docs / config UIs. */
1293
1430
  declare const MCP_TOOL_NAMES: ReadonlyArray<McpToolName>;
1294
1431
 
1295
- export { type Assertion, type AttachmentRef, type AwsSigV4Auth, type BodyType, type ConnectedRepo, type ContextExtraction, DEFAULT_WORKSPACE_NAME, type DigestAuth, type EnvPriorityRef, type Environment, type EnvironmentVariable, type EnvironmentVariableOverride, type ExecutionPlan, FONT_SIZE_PERCENT_DEFAULT, FONT_SIZE_PERCENT_MAX, FONT_SIZE_PERCENT_MIN, FONT_SIZE_PERCENT_STEP, type Folder, type FolderNode, type FontFamilyId, type FormDataRow, type GitHubSession, type GlobalFileAsset, type GlobalGraphQL, type GlobalSchema, type HawkAuth, type HttpMethod, type JwtBearerAuth, type LinkedSnapshot, type LinkedWorkspace, type LocalAttachmentCacheEntry, MCP_TOOL_NAMES, type McpError, type McpToolName, type MockConditionClause, type MockConditionOp, type MockConditionScope, type MockEndpoint, type MockMultiplierSource, type MockMultiplierSourceKind, type MockParamDef, type MockRequestSchema, type MockResponseBody, type MockResponseBodyType, type MockResponseConfig, type MockResponseMultiplier, type MockResponseRule, type MockRuntime, type MockRuntimeEntry, type MockServer, type MockServerSource, type MockValidationKind, type MockValidationRule, type NtlmAuth, type OAuth2AuthCodeAuth, type OAuth2ClientCredentialsAuth, type OAuth2DeviceAuth, type OAuth2ImplicitAuth, type OAuth2PasswordAuth, type OAuth2PkceAuth, type OAuth2TokenState, type PanelId, type PlanRun, REQUEST_AUTH_TYPES, RUN_BODY_PREVIEW_LIMIT, type ReleaseHistory, type ReleaseVersion, type Request, type RequestAuth, type RequestAuthType, type RequestBody, type RequestOverride, type RequestOverridePatch, type RequestRun, type RetiredBranch, type SecretCryptoMeta, type SecretEntry, type SecretIndex, type SecretKeyMeta, type SecretUsage, type SyncSnapshot, type ThemeId, type ValidationResult, type WorkingBranch, type WorkspaceLocal, type WorkspaceSnapshot, type WorkspaceSnapshotLedger, type WorkspaceSnapshotTrigger, type WorkspaceSynced, coerceMockResponseBodyTypeForStatus, defaultAuthFor, envPriorityDisplayName, envPriorityKey, envPriorityRefEqual, formatBytes, generateId, getAllowedMockResponseBodyTypes, makeDefaultMockResponse, makeDefaultMockResponseBody, makeDefaultRequestSchema, normalizeAuth, parseEnvPriorityKey, safeExternalHref, utf8ByteLength, validateAwsRegion, validateEnvVarName, validateHttpHeaderName, validateJsonPath, validateJsonString, validateMockPath, validatePRTitle, validatePlanName, validatePositiveDuration, validateRegex, validateUrl };
1432
+ export { type Assertion, type AssetGitRef, type AssetUsage, type AttachmentRef, type AwsSigV4Auth, type BodyType, type ConnectedRepo, type ContextExtraction, DEFAULT_WORKSPACE_NAME, type DigestAuth, type EnvPriorityRef, type Environment, type EnvironmentVariable, type EnvironmentVariableOverride, type ExecutionPlan, FONT_SIZE_PERCENT_DEFAULT, FONT_SIZE_PERCENT_MAX, FONT_SIZE_PERCENT_MIN, FONT_SIZE_PERCENT_STEP, type Folder, type FolderNode, type FontFamilyId, type FormDataRow, type GitHubSession, type GlobalFileAsset, type GlobalGraphQL, type GlobalSchema, type HawkAuth, type HttpMethod, type JwtBearerAuth, type LinkedSnapshot, type LinkedWorkspace, type LocalAttachmentCacheEntry, MAX_RESPONSE_MULTIPLIERS, MAX_RESPONSE_RULE_CONDITIONS, MCP_TOOL_NAMES, type McpError, type McpToolName, type MockConditionClause, type MockConditionOp, type MockConditionScope, type MockEndpoint, type MockMultiplierSource, type MockMultiplierSourceKind, type MockParamDef, type MockRequestSchema, type MockResponseBody, type MockResponseBodyType, type MockResponseConfig, type MockResponseMultiplier, type MockResponseRule, type MockRuntime, type MockRuntimeEntry, type MockServer, type MockServerSource, type MockValidationKind, type MockValidationRule, type NtlmAuth, type OAuth2AuthCodeAuth, type OAuth2ClientCredentialsAuth, type OAuth2DeviceAuth, type OAuth2ImplicitAuth, type OAuth2PasswordAuth, type OAuth2PkceAuth, type OAuth2TokenState, type PanelId, type PendingFileUpload, type PlanRun, REQUEST_AUTH_TYPES, RUN_BODY_PREVIEW_LIMIT, type ReleaseHistory, type ReleaseVersion, type Request, type RequestAuth, type RequestAuthType, type RequestBody, type RequestOverride, type RequestOverridePatch, type RequestRun, type RetiredBranch, type SecretCryptoMeta, type SecretEntry, type SecretIndex, type SecretKeyMeta, type SecretUsage, type SyncSnapshot, type ThemeId, type ValidationResult, type WorkingBranch, type WorkspaceLocal, type WorkspaceSnapshot, type WorkspaceSnapshotLedger, type WorkspaceSnapshotTrigger, type WorkspaceSynced, coerceMockResponseBodyTypeForStatus, defaultAuthFor, envPriorityDisplayName, envPriorityKey, envPriorityRefEqual, formatBytes, generateId, getAllowedMockResponseBodyTypes, makeDefaultMockResponse, makeDefaultMockResponseBody, makeDefaultRequestSchema, normalizeAuth, parseEnvPriorityKey, safeExternalHref, utf8ByteLength, validateAwsRegion, validateEnvVarName, validateHttpHeaderName, validateJsonPath, validateJsonString, validateMockPath, validatePRTitle, validatePlanName, validatePositiveDuration, validateRegex, validateUrl };
package/dist/index.d.ts CHANGED
@@ -132,15 +132,26 @@ interface MockResponseConfig {
132
132
  delayMs?: number;
133
133
  /**
134
134
  * Optional response-shape multipliers. At runtime, each multiplier reads a
135
- * value from the request (a query/path/header param or a JSON-path slice
136
- * of the request body) and repeats the array element at `targetJsonPath`
137
- * inside the response body that many times. Used to drive page-size
138
- * aware mock responses without templating the body manually.
135
+ * value from the request (a query/path/header param or a JSON-path slice of
136
+ * the request body) and repeats the array element at `targetJsonPath` inside
137
+ * the response body that many times. Used to drive page-size aware mock
138
+ * responses without templating the body manually.
139
139
  *
140
- * Only fires when `body.type === 'json'`; ignored otherwise.
140
+ * The persisted shape is an array so the feature can grow to N multipliers
141
+ * without a schema migration. For now the authoring surfaces (editors, MCP
142
+ * tools) cap the list at {@link MAX_RESPONSE_MULTIPLIERS}; the runtime applies
143
+ * every entry it finds (so a future cap bump — or a hand-edit — needs no
144
+ * engine change). Only fires when `body.type === 'json'`; ignored otherwise.
141
145
  */
142
146
  multipliers?: MockResponseMultiplier[];
143
147
  }
148
+ /**
149
+ * How many response multipliers the authoring surfaces (desktop/web editor,
150
+ * VS Code lenses, MCP tools) allow per response. The persisted shape is an
151
+ * array, so raising this to N — or removing the gate — is the ONLY change
152
+ * needed to support multiple multipliers; no data migration, no engine change.
153
+ */
154
+ declare const MAX_RESPONSE_MULTIPLIERS = 1;
144
155
  type MockMultiplierSourceKind = 'query' | 'pathParam' | 'header' | 'body-json-path';
145
156
  interface MockMultiplierSource {
146
157
  kind: MockMultiplierSourceKind;
@@ -227,6 +238,14 @@ interface MockResponseRule {
227
238
  when: MockConditionClause[];
228
239
  response: MockResponseConfig;
229
240
  }
241
+ /**
242
+ * How many `when` clauses the authoring surfaces (VS Code lenses, desktop/web
243
+ * editor, MCP tools) allow per response rule. The persisted shape is an array
244
+ * and the runtime AND-combines every clause it finds, so raising this to N — or
245
+ * removing the gate — is the ONLY change needed to support multi-clause rules;
246
+ * no data migration, no engine change. Mirrors {@link MAX_RESPONSE_MULTIPLIERS}.
247
+ */
248
+ declare const MAX_RESPONSE_RULE_CONDITIONS = 1;
230
249
  interface MockEndpoint {
231
250
  /** Stable id; survives spec re-parses so per-endpoint overrides keep matching. */
232
251
  id: string;
@@ -486,6 +505,38 @@ interface GlobalGraphQL {
486
505
  createdAt: string;
487
506
  updatedAt: string;
488
507
  }
508
+ /**
509
+ * Pointer to a verified-good copy of a Global File Asset's bytes on a
510
+ * specific Git ref. Each asset can carry up to two of these — one for
511
+ * the consumer's working branch and one for the base branch the working
512
+ * branch was forked from — and the cleanup invariant drops the working
513
+ * ref once the base ref holds the same blob (single source of truth).
514
+ *
515
+ * Populated lazily — never at upload time. The first push promotes the
516
+ * pending upload to `workingBranchRef`; the next refresh after the PR
517
+ * merges promotes to `baseBranchRef`. See
518
+ * docs/architecture/platform.md for the full state machine.
519
+ */
520
+ interface AssetGitRef {
521
+ /** Branch the asset is known to live on. */
522
+ branchName: string;
523
+ /**
524
+ * GitHub blob SHA at the most recent successful verification. Drives
525
+ * the cleanup invariant — when both refs return the same `blobSha` the
526
+ * working ref is redundant and gets dropped. Optional because legacy
527
+ * entries persisted before this field existed; consumers treat absent
528
+ * as "not yet verified."
529
+ */
530
+ blobSha?: string;
531
+ /**
532
+ * Commit SHA the ref was first recorded at. Used for display
533
+ * ("On main · since v2.3.1") and for the "branch retargeted" detection
534
+ * path where the same branchName resolves to a different blob.
535
+ */
536
+ commitSha?: string;
537
+ /** ISO timestamp of the last successful read of this ref. */
538
+ verifiedAt: string;
539
+ }
489
540
  interface GlobalFileAsset {
490
541
  id: string;
491
542
  name: string;
@@ -497,6 +548,55 @@ interface GlobalFileAsset {
497
548
  sha256?: string;
498
549
  createdAt: string;
499
550
  updatedAt: string;
551
+ /**
552
+ * Provenance pointer to the asset's bytes on the consumer's currently
553
+ * connected working branch. Set by the push flow after `updateRef`
554
+ * resolves with the GitHub blob sha. Dropped by the cleanup invariant
555
+ * when `baseBranchRef` holds the same blob. Optional — pre-1.0.9 docs
556
+ * and freshly-uploaded-but-unpushed assets leave it `undefined`.
557
+ */
558
+ workingBranchRef?: AssetGitRef | null;
559
+ /**
560
+ * Provenance pointer to the asset's bytes on the base branch the
561
+ * working branch was forked from (usually `main`). Set by the refresh
562
+ * verification probe once the PR merges. Optional — assets that have
563
+ * never been merged leave it `undefined`.
564
+ */
565
+ baseBranchRef?: AssetGitRef | null;
566
+ }
567
+ /**
568
+ * Local-only buffer recording an asset whose bytes are in IDB but have
569
+ * not yet been pushed to any Git ref. Keyed by `globalFileAssetId` so
570
+ * the desktop / web can render an "Uploaded locally" state pill and the
571
+ * push flow knows which slots still need to be uploaded as blobs. Dropped
572
+ * by the push flow after `globalAsset.markPushed` lands.
573
+ */
574
+ interface PendingFileUpload {
575
+ slotId: string;
576
+ filename: string;
577
+ mimeType: string;
578
+ sha256: string;
579
+ size: number;
580
+ /** ISO timestamp the file was dropped into the studio. */
581
+ queuedAt: string;
582
+ }
583
+ /**
584
+ * Where a Global File Asset is referenced inside the current synced doc.
585
+ * Recomputed by `assetUsageAggregator` after every `commitSynced`. Used
586
+ * to surface "Used in N places" in the Global Assets panel, the form-data
587
+ * row, the binary body, and the mock-response editors, and to flag
588
+ * zero-use orphans for one-click cleanup.
589
+ */
590
+ interface AssetUsage {
591
+ /** Request ids whose body binds this asset. */
592
+ requests: string[];
593
+ /** Mock endpoints whose responses bind this asset. */
594
+ mockEndpoints: Array<{
595
+ mockId: string;
596
+ endpointId: string;
597
+ }>;
598
+ /** Total reference count — denormalised for cheap badge rendering. */
599
+ total: number;
500
600
  }
501
601
  type RequestAuth = {
502
602
  type: 'none';
@@ -677,7 +777,7 @@ interface LocalAttachmentCacheEntry {
677
777
  /**
678
778
  * Local-only path or storage URI where this device can read the bytes for
679
779
  * execution. Browser builds use an IndexedDB URI; CLI runs use an absolute
680
- * filesystem path under `.apicircle/attachments/`.
780
+ * filesystem path under `.apicircle/workspace-<id>/attachments/`.
681
781
  */
682
782
  localPath: string;
683
783
  storage: 'indexeddb' | 'filesystem';
@@ -754,6 +854,10 @@ interface LinkedWorkspace {
754
854
  kind: 'private' | 'public';
755
855
  name: string;
756
856
  description?: string;
857
+ /** The remote workspace's `workspaceId` (from the source's registry).
858
+ * Needed to resolve per-workspace paths (attachments, workspace.json)
859
+ * when fetching from the source repo. */
860
+ sourceWorkspaceId: string;
757
861
  source: {
758
862
  provider: 'github';
759
863
  repoFullName: string;
@@ -900,6 +1004,39 @@ interface WorkspaceLocal {
900
1004
  * eviction.
901
1005
  */
902
1006
  snapshots: WorkspaceSnapshotLedger;
1007
+ /**
1008
+ * Pre-push buffer for Global File Asset bytes. Each entry mirrors the
1009
+ * IDB attachment record (which stays the authoritative byte store) but
1010
+ * is keyed by `globalFileAssetId` instead of `slotId`, making it easy
1011
+ * for the push flow + the status-pill UI to ask "is this asset still
1012
+ * pending upload?" without scanning IDB. Dropped per-asset after the
1013
+ * push promotes the asset to `workingBranchRef`.
1014
+ */
1015
+ pendingFileUploads?: Record<string, PendingFileUpload>;
1016
+ /**
1017
+ * Cross-cutting reference index for Global File Assets. Recomputed by
1018
+ * `assetUsageAggregator` whenever `commitSynced` runs, mirroring the
1019
+ * `secretIndex.entries[].usedIn` pattern. Local-only because it's pure
1020
+ * cache — the truth lives in `synced.collections.requests` and
1021
+ * `synced.mockServers`.
1022
+ */
1023
+ assetUsageIndex?: Record<string, AssetUsage>;
1024
+ /**
1025
+ * Slot ids whose attachment blob needs to be DELETED from the working
1026
+ * branch on the next push. Queued by `removeGlobalFileAsset` (and the
1027
+ * headless `globalAsset.removeFile` patch) when the asset being
1028
+ * deleted had any push provenance (`workingBranchRef` or
1029
+ * `baseBranchRef`). The push emits
1030
+ * `{path: '.apicircle/workspace-<id>/attachments/<slotId>', sha: null}`
1031
+ * tree entries layered over `base_tree`, which GitHub treats as
1032
+ * deletions. After a successful push, the queue is cleared — the
1033
+ * deletion is durable on the working branch, and the eventual PR
1034
+ * merge propagates it to the base branch.
1035
+ *
1036
+ * Without this queue, the asset would be removed from `workspace.json`
1037
+ * but the orphan blob would persist on the remote tree forever.
1038
+ */
1039
+ pendingAttachmentDeletes?: string[];
903
1040
  }
904
1041
  interface WorkspaceLocalSettings {
905
1042
  validateOnSend: boolean;
@@ -1283,7 +1420,7 @@ declare const REQUEST_AUTH_TYPES: ReadonlyArray<RequestAuthType>;
1283
1420
  * clients can group them in their UI. Keep in sync with the registry in
1284
1421
  * `packages/mcp-server/src/tools/registry.ts`.
1285
1422
  */
1286
- type McpToolName = 'import.curl' | 'import.openapi' | 'import.postman' | 'import.insomnia' | 'import.har' | 'generate.code' | 'workspace.list' | 'workspace.read' | 'workspace.write' | 'request.create' | 'request.read' | 'request.update' | 'request.delete' | 'folder.create' | 'folder.read' | 'folder.update' | 'folder.delete' | 'folder.export_json' | 'folder.import_json' | 'environment.create' | 'environment.read' | 'environment.update' | 'environment.delete' | 'environment.set_active' | 'environment.set_priority' | 'environment.export' | 'environment.import' | 'plan.create' | 'plan.run' | 'plan.read' | 'plan.update' | 'plan.delete' | 'plan.add_step' | 'plan.remove_step' | 'plan.reorder_steps' | 'plan.set_variables' | 'assertion.create' | 'assertion.read' | 'assertion.update' | 'assertion.delete' | 'history.list_runs' | 'history.get_run' | 'history.delete_run' | 'history.purge_by_age' | 'codebase.extract_collection' | 'prompt.create_environment' | 'prompt.create_assertion' | 'prompt.create_plan' | 'prompt.create_request' | 'prompt.update_request' | 'prompt.create_folder_tree' | 'prompt.add_plan_steps' | 'prompt.set_plan_variables' | 'prompt.create_mock_server' | 'prompt.add_mock_endpoint' | 'prompt.set_endpoint_validation_rules' | 'prompt.set_endpoint_response_rules' | 'prompt.set_endpoint_multipliers' | 'mock.create_from_openapi' | 'mock.create_from_postman' | 'mock.create_from_insomnia' | 'mock.create_manual' | 'mock.list' | 'mock.list_endpoints' | 'mock.start' | 'mock.stop' | 'mock.delete' | 'mock.add_endpoint' | 'mock.update_endpoint' | 'mock.delete_endpoint' | 'mock.set_validation_rules' | 'mock.set_response_rules' | 'mock.set_multipliers' | 'mock.import_postman_mock_collection';
1423
+ type McpToolName = 'import.curl' | 'import.openapi' | 'import.postman' | 'import.insomnia' | 'import.har' | 'generate.code' | 'workspace.list' | 'workspace.read' | 'workspace.write' | 'request.create' | 'request.read' | 'request.update' | 'request.delete' | 'folder.create' | 'folder.read' | 'folder.update' | 'folder.delete' | 'folder.export_json' | 'folder.import_json' | 'environment.create' | 'environment.read' | 'environment.update' | 'environment.delete' | 'environment.set_active' | 'environment.set_priority' | 'environment.export' | 'environment.import' | 'plan.create' | 'plan.run' | 'plan.read' | 'plan.update' | 'plan.delete' | 'plan.add_step' | 'plan.remove_step' | 'plan.reorder_steps' | 'plan.set_variables' | 'assertion.create' | 'assertion.read' | 'assertion.update' | 'assertion.delete' | 'history.list_runs' | 'history.get_run' | 'history.delete_run' | 'history.purge_by_age' | 'codebase.extract_collection' | 'prompt.create_environment' | 'prompt.create_assertion' | 'prompt.create_plan' | 'prompt.create_request' | 'prompt.update_request' | 'prompt.create_folder_tree' | 'prompt.add_plan_steps' | 'prompt.set_plan_variables' | 'prompt.create_mock_server' | 'prompt.add_mock_endpoint' | 'prompt.set_endpoint_validation_rules' | 'prompt.set_endpoint_response_rules' | 'prompt.set_endpoint_multipliers' | 'prompt.set_endpoint_request_schema' | 'assets.list_files' | 'assets.create_file' | 'assets.update_file' | 'assets.delete_file' | 'mock.create_from_openapi' | 'mock.create_from_postman' | 'mock.create_from_insomnia' | 'mock.create_manual' | 'mock.list' | 'mock.list_endpoints' | 'mock.start' | 'mock.stop' | 'mock.delete' | 'mock.add_endpoint' | 'mock.update_endpoint' | 'mock.delete_endpoint' | 'mock.set_validation_rules' | 'mock.set_response_rules' | 'mock.set_multipliers' | 'mock.set_request_schema' | 'mock.set_default_port' | 'mock.import_postman_mock_collection' | 'release.list' | 'release.publish' | 'release.deprecate' | 'release.yank' | 'linked.list' | 'linked.get' | 'linked.set_config' | 'linked.unlink' | 'linked.link' | 'linked.refresh' | 'release.tag' | 'repo.set_topics' | 'marketplace.search';
1287
1424
  interface McpError {
1288
1425
  code: 'invalid_input' | 'not_found' | 'conflict' | 'unsupported' | 'internal';
1289
1426
  message: string;
@@ -1292,4 +1429,4 @@ interface McpError {
1292
1429
  /** Helper: full enumeration of tool names — useful for the docs / config UIs. */
1293
1430
  declare const MCP_TOOL_NAMES: ReadonlyArray<McpToolName>;
1294
1431
 
1295
- export { type Assertion, type AttachmentRef, type AwsSigV4Auth, type BodyType, type ConnectedRepo, type ContextExtraction, DEFAULT_WORKSPACE_NAME, type DigestAuth, type EnvPriorityRef, type Environment, type EnvironmentVariable, type EnvironmentVariableOverride, type ExecutionPlan, FONT_SIZE_PERCENT_DEFAULT, FONT_SIZE_PERCENT_MAX, FONT_SIZE_PERCENT_MIN, FONT_SIZE_PERCENT_STEP, type Folder, type FolderNode, type FontFamilyId, type FormDataRow, type GitHubSession, type GlobalFileAsset, type GlobalGraphQL, type GlobalSchema, type HawkAuth, type HttpMethod, type JwtBearerAuth, type LinkedSnapshot, type LinkedWorkspace, type LocalAttachmentCacheEntry, MCP_TOOL_NAMES, type McpError, type McpToolName, type MockConditionClause, type MockConditionOp, type MockConditionScope, type MockEndpoint, type MockMultiplierSource, type MockMultiplierSourceKind, type MockParamDef, type MockRequestSchema, type MockResponseBody, type MockResponseBodyType, type MockResponseConfig, type MockResponseMultiplier, type MockResponseRule, type MockRuntime, type MockRuntimeEntry, type MockServer, type MockServerSource, type MockValidationKind, type MockValidationRule, type NtlmAuth, type OAuth2AuthCodeAuth, type OAuth2ClientCredentialsAuth, type OAuth2DeviceAuth, type OAuth2ImplicitAuth, type OAuth2PasswordAuth, type OAuth2PkceAuth, type OAuth2TokenState, type PanelId, type PlanRun, REQUEST_AUTH_TYPES, RUN_BODY_PREVIEW_LIMIT, type ReleaseHistory, type ReleaseVersion, type Request, type RequestAuth, type RequestAuthType, type RequestBody, type RequestOverride, type RequestOverridePatch, type RequestRun, type RetiredBranch, type SecretCryptoMeta, type SecretEntry, type SecretIndex, type SecretKeyMeta, type SecretUsage, type SyncSnapshot, type ThemeId, type ValidationResult, type WorkingBranch, type WorkspaceLocal, type WorkspaceSnapshot, type WorkspaceSnapshotLedger, type WorkspaceSnapshotTrigger, type WorkspaceSynced, coerceMockResponseBodyTypeForStatus, defaultAuthFor, envPriorityDisplayName, envPriorityKey, envPriorityRefEqual, formatBytes, generateId, getAllowedMockResponseBodyTypes, makeDefaultMockResponse, makeDefaultMockResponseBody, makeDefaultRequestSchema, normalizeAuth, parseEnvPriorityKey, safeExternalHref, utf8ByteLength, validateAwsRegion, validateEnvVarName, validateHttpHeaderName, validateJsonPath, validateJsonString, validateMockPath, validatePRTitle, validatePlanName, validatePositiveDuration, validateRegex, validateUrl };
1432
+ export { type Assertion, type AssetGitRef, type AssetUsage, type AttachmentRef, type AwsSigV4Auth, type BodyType, type ConnectedRepo, type ContextExtraction, DEFAULT_WORKSPACE_NAME, type DigestAuth, type EnvPriorityRef, type Environment, type EnvironmentVariable, type EnvironmentVariableOverride, type ExecutionPlan, FONT_SIZE_PERCENT_DEFAULT, FONT_SIZE_PERCENT_MAX, FONT_SIZE_PERCENT_MIN, FONT_SIZE_PERCENT_STEP, type Folder, type FolderNode, type FontFamilyId, type FormDataRow, type GitHubSession, type GlobalFileAsset, type GlobalGraphQL, type GlobalSchema, type HawkAuth, type HttpMethod, type JwtBearerAuth, type LinkedSnapshot, type LinkedWorkspace, type LocalAttachmentCacheEntry, MAX_RESPONSE_MULTIPLIERS, MAX_RESPONSE_RULE_CONDITIONS, MCP_TOOL_NAMES, type McpError, type McpToolName, type MockConditionClause, type MockConditionOp, type MockConditionScope, type MockEndpoint, type MockMultiplierSource, type MockMultiplierSourceKind, type MockParamDef, type MockRequestSchema, type MockResponseBody, type MockResponseBodyType, type MockResponseConfig, type MockResponseMultiplier, type MockResponseRule, type MockRuntime, type MockRuntimeEntry, type MockServer, type MockServerSource, type MockValidationKind, type MockValidationRule, type NtlmAuth, type OAuth2AuthCodeAuth, type OAuth2ClientCredentialsAuth, type OAuth2DeviceAuth, type OAuth2ImplicitAuth, type OAuth2PasswordAuth, type OAuth2PkceAuth, type OAuth2TokenState, type PanelId, type PendingFileUpload, type PlanRun, REQUEST_AUTH_TYPES, RUN_BODY_PREVIEW_LIMIT, type ReleaseHistory, type ReleaseVersion, type Request, type RequestAuth, type RequestAuthType, type RequestBody, type RequestOverride, type RequestOverridePatch, type RequestRun, type RetiredBranch, type SecretCryptoMeta, type SecretEntry, type SecretIndex, type SecretKeyMeta, type SecretUsage, type SyncSnapshot, type ThemeId, type ValidationResult, type WorkingBranch, type WorkspaceLocal, type WorkspaceSnapshot, type WorkspaceSnapshotLedger, type WorkspaceSnapshotTrigger, type WorkspaceSynced, coerceMockResponseBodyTypeForStatus, defaultAuthFor, envPriorityDisplayName, envPriorityKey, envPriorityRefEqual, formatBytes, generateId, getAllowedMockResponseBodyTypes, makeDefaultMockResponse, makeDefaultMockResponseBody, makeDefaultRequestSchema, normalizeAuth, parseEnvPriorityKey, safeExternalHref, utf8ByteLength, validateAwsRegion, validateEnvVarName, validateHttpHeaderName, validateJsonPath, validateJsonString, validateMockPath, validatePRTitle, validatePlanName, validatePositiveDuration, validateRegex, validateUrl };
package/dist/index.js CHANGED
@@ -396,6 +396,11 @@ var MCP_TOOL_NAMES = [
396
396
  "prompt.set_endpoint_validation_rules",
397
397
  "prompt.set_endpoint_response_rules",
398
398
  "prompt.set_endpoint_multipliers",
399
+ "prompt.set_endpoint_request_schema",
400
+ "assets.list_files",
401
+ "assets.create_file",
402
+ "assets.update_file",
403
+ "assets.delete_file",
399
404
  "mock.create_from_openapi",
400
405
  "mock.create_from_postman",
401
406
  "mock.create_from_insomnia",
@@ -411,10 +416,27 @@ var MCP_TOOL_NAMES = [
411
416
  "mock.set_validation_rules",
412
417
  "mock.set_response_rules",
413
418
  "mock.set_multipliers",
414
- "mock.import_postman_mock_collection"
419
+ "mock.set_request_schema",
420
+ "mock.set_default_port",
421
+ "mock.import_postman_mock_collection",
422
+ "release.list",
423
+ "release.publish",
424
+ "release.deprecate",
425
+ "release.yank",
426
+ "linked.list",
427
+ "linked.get",
428
+ "linked.set_config",
429
+ "linked.unlink",
430
+ "linked.link",
431
+ "linked.refresh",
432
+ "release.tag",
433
+ "repo.set_topics",
434
+ "marketplace.search"
415
435
  ];
416
436
 
417
437
  // src/mock.ts
438
+ var MAX_RESPONSE_MULTIPLIERS = 1;
439
+ var MAX_RESPONSE_RULE_CONDITIONS = 1;
418
440
  var NO_BODY_STATUSES = /* @__PURE__ */ new Set([100, 101, 102, 103, 204, 205, 304]);
419
441
  function getAllowedMockResponseBodyTypes(status) {
420
442
  if (NO_BODY_STATUSES.has(status)) return ["none"];
@@ -457,6 +479,8 @@ export {
457
479
  FONT_SIZE_PERCENT_MAX,
458
480
  FONT_SIZE_PERCENT_MIN,
459
481
  FONT_SIZE_PERCENT_STEP,
482
+ MAX_RESPONSE_MULTIPLIERS,
483
+ MAX_RESPONSE_RULE_CONDITIONS,
460
484
  MCP_TOOL_NAMES,
461
485
  REQUEST_AUTH_TYPES,
462
486
  RUN_BODY_PREVIEW_LIMIT,