@mycadet/assistant 0.12.11 → 0.13.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.
Files changed (176) hide show
  1. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +2 -2
  2. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/ingress.ts +2 -2
  3. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +2 -2
  4. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/ingress.ts +2 -2
  5. package/node_modules/@mycadet/gateway-client/src/gateway-ipc-contracts.ts +0 -20
  6. package/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +2 -2
  7. package/node_modules/@mycadet/service-contracts/src/ingress.ts +2 -2
  8. package/openapi.yaml +2 -708
  9. package/package.json +2 -3
  10. package/scripts/sync-web-search-catalog.ts +1 -2
  11. package/src/__tests__/cloud-profile-guard.test.ts +2 -2
  12. package/src/__tests__/config-schema.test.ts +6 -38
  13. package/src/__tests__/conversation-queue.test.ts +45 -6
  14. package/src/__tests__/db-readiness-http-gate.test.ts +0 -6
  15. package/src/__tests__/persist-onboarding-artifacts.test.ts +0 -1
  16. package/src/__tests__/persona-resolver.test.ts +0 -51
  17. package/src/__tests__/provider-cloud-proxy-integration.test.ts +2 -110
  18. package/src/__tests__/run-due-schedules.test.ts +0 -4
  19. package/src/__tests__/schedule-store.test.ts +0 -12
  20. package/src/__tests__/stt-stream-session.test.ts +4 -4
  21. package/src/__tests__/telephony-tts-guard.test.ts +2 -50
  22. package/src/__tests__/voice-config-update.test.ts +12 -167
  23. package/src/__tests__/web-search-catalog-parity.test.ts +0 -2
  24. package/src/__tests__/workspace-migration-130-speech-mode-to-provider.test.ts +9 -7
  25. package/src/__tests__/workspace-migration-132-web-search-mode-to-provider.test.ts +6 -6
  26. package/src/calls/__tests__/voice-session-bridge.test.ts +1 -4
  27. package/src/calls/resolve-call-tts-provider.ts +6 -25
  28. package/src/calls/telephony-credential-preflight.ts +0 -10
  29. package/src/calls/telephony-tts-capability.ts +1 -17
  30. package/src/cli/commands/tts.ts +1 -2
  31. package/src/cli/index.help.ts +0 -2
  32. package/src/cli/program.ts +0 -2
  33. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +4 -42
  34. package/src/config/schemas/__tests__/stt.test.ts +10 -14
  35. package/src/config/schemas/services.ts +5 -6
  36. package/src/config/schemas/stt.ts +1 -3
  37. package/src/config/schemas/tts.ts +1 -30
  38. package/src/daemon/daemon-readiness.ts +4 -29
  39. package/src/daemon/lifecycle.ts +0 -31
  40. package/src/daemon/providers-setup.ts +0 -8
  41. package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -1
  42. package/src/heartbeat/heartbeat-service.ts +1 -66
  43. package/src/ipc/__tests__/db-readiness-ipc-gate.test.ts +1 -9
  44. package/src/live-voice/__tests__/live-voice-credential-preflight.test.ts +0 -44
  45. package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +4 -6
  46. package/src/live-voice/__tests__/live-voice-stt.test.ts +1 -1
  47. package/src/live-voice/live-voice-credential-preflight.ts +9 -33
  48. package/src/live-voice/live-voice-session.ts +10 -6
  49. package/src/live-voice/live-voice-tts.ts +1 -8
  50. package/src/plugins/defaults/memory/worker.ts +3 -3
  51. package/src/prompts/persona-resolver.ts +0 -35
  52. package/src/providers/__tests__/search-provider-catalog.test.ts +5 -8
  53. package/src/providers/__tests__/voice-error-copy.test.ts +9 -10
  54. package/src/providers/search-provider-catalog.ts +7 -39
  55. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +3 -47
  56. package/src/providers/speech-to-text/__tests__/resolve.test.ts +6 -372
  57. package/src/providers/speech-to-text/provider-catalog.ts +2 -73
  58. package/src/providers/speech-to-text/resolve.ts +3 -120
  59. package/src/runtime/http-router-types.ts +1 -3
  60. package/src/runtime/http-server.ts +1 -1
  61. package/src/runtime/routes/__tests__/tts-routes.test.ts +2 -6
  62. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +7 -7
  63. package/src/runtime/routes/index.ts +0 -4
  64. package/src/runtime/routes/live-voice-routes.test.ts +4 -11
  65. package/src/runtime/routes/live-voice-routes.ts +8 -11
  66. package/src/runtime/routes/secret-routes.ts +0 -6
  67. package/src/runtime/routes/tts-routes.ts +0 -38
  68. package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1 -7
  69. package/src/schedule/__tests__/worker-mcp-readiness.test.ts +0 -4
  70. package/src/schedule/schedule-store.ts +0 -7
  71. package/src/schedule/scheduler.ts +0 -5
  72. package/src/schedule/worker.ts +1 -1
  73. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +2 -10
  74. package/src/stt/daemon-batch-transcriber.ts +4 -38
  75. package/src/stt/types.ts +1 -9
  76. package/src/tools/network/__tests__/web-search.test.ts +3 -250
  77. package/src/tools/network/web-search.ts +4 -165
  78. package/src/tts/__tests__/provider-resolution.test.ts +0 -5
  79. package/src/tts/provider-catalog.ts +0 -4
  80. package/src/tts/types.ts +0 -1
  81. package/src/__tests__/cloud-speech-defaults.test.ts +0 -330
  82. package/src/__tests__/migration-cross-version-compatibility.test.ts +0 -1708
  83. package/src/__tests__/migration-export-http.test.ts +0 -557
  84. package/src/__tests__/migration-export-streaming.test.ts +0 -350
  85. package/src/__tests__/migration-export-to-gcs.test.ts +0 -706
  86. package/src/__tests__/migration-import-commit-http.test.ts +0 -1176
  87. package/src/__tests__/migration-import-from-gcs.test.ts +0 -534
  88. package/src/__tests__/migration-import-from-path.test.ts +0 -324
  89. package/src/__tests__/migration-import-from-url.test.ts +0 -588
  90. package/src/__tests__/migration-import-preflight-http.test.ts +0 -739
  91. package/src/__tests__/migration-jobs-status.test.ts +0 -139
  92. package/src/__tests__/migration-parity-persistence.test.ts +0 -1891
  93. package/src/__tests__/migration-transport.test.ts +0 -1089
  94. package/src/__tests__/migration-validate-http.test.ts +0 -634
  95. package/src/__tests__/migration-wizard.test.ts +0 -1395
  96. package/src/__tests__/rebind-secrets-screen.test.ts +0 -876
  97. package/src/__tests__/sanitize-config-for-transfer.test.ts +0 -259
  98. package/src/__tests__/transfer-progress-screen.test.ts +0 -1217
  99. package/src/__tests__/validation-results-screen.test.ts +0 -1130
  100. package/src/__tests__/vbundle-pax-and-symlink.test.ts +0 -147
  101. package/src/background-wake/background-wake-routes.test.ts +0 -906
  102. package/src/background-wake/cloud-client.test.ts +0 -328
  103. package/src/background-wake/cloud-client.ts +0 -196
  104. package/src/background-wake/next-wake.test.ts +0 -335
  105. package/src/background-wake/next-wake.ts +0 -188
  106. package/src/background-wake/publisher.ts +0 -93
  107. package/src/background-wake/wake-intent-hooks.test.ts +0 -234
  108. package/src/cli/commands/__tests__/backup.test.ts +0 -363
  109. package/src/cli/commands/backup.help.ts +0 -180
  110. package/src/cli/commands/backup.ts +0 -398
  111. package/src/cloud/cloud-speech.test.ts +0 -335
  112. package/src/cloud/cloud-speech.ts +0 -300
  113. package/src/config/cloud-speech-defaults.ts +0 -300
  114. package/src/config/sanitize-for-transfer.ts +0 -111
  115. package/src/live-voice/__tests__/live-voice-cloud-speech-fallback.test.ts +0 -250
  116. package/src/providers/speech-to-text/__tests__/cadet-cloud-realtime.test.ts +0 -457
  117. package/src/providers/speech-to-text/__tests__/cadet-cloud.test.ts +0 -271
  118. package/src/providers/speech-to-text/__tests__/cadet-speech-relay-connection.test.ts +0 -126
  119. package/src/providers/speech-to-text/cadet-cloud-flux-realtime.ts +0 -309
  120. package/src/providers/speech-to-text/cadet-cloud-realtime.ts +0 -315
  121. package/src/providers/speech-to-text/cadet-cloud.ts +0 -108
  122. package/src/providers/speech-to-text/cadet-speech-relay-connection.ts +0 -176
  123. package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +0 -254
  124. package/src/runtime/migrations/__tests__/job-registry.test.ts +0 -346
  125. package/src/runtime/migrations/__tests__/origin-mode.test.ts +0 -62
  126. package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +0 -184
  127. package/src/runtime/migrations/__tests__/staged-import-path.test.ts +0 -110
  128. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +0 -112
  129. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +0 -285
  130. package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +0 -126
  131. package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +0 -253
  132. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +0 -208
  133. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +0 -485
  134. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +0 -349
  135. package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +0 -196
  136. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +0 -551
  137. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +0 -428
  138. package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +0 -220
  139. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +0 -1823
  140. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +0 -598
  141. package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +0 -463
  142. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -538
  143. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +0 -515
  144. package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +0 -453
  145. package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +0 -319
  146. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +0 -240
  147. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +0 -473
  148. package/src/runtime/migrations/gcs-signed-url.ts +0 -190
  149. package/src/runtime/migrations/job-registry.ts +0 -297
  150. package/src/runtime/migrations/migration-transport.ts +0 -612
  151. package/src/runtime/migrations/migration-wizard.ts +0 -747
  152. package/src/runtime/migrations/origin-mode.ts +0 -42
  153. package/src/runtime/migrations/rebind-secrets-screen.ts +0 -412
  154. package/src/runtime/migrations/staged-import-path.ts +0 -116
  155. package/src/runtime/migrations/transfer-progress-screen.ts +0 -323
  156. package/src/runtime/migrations/validation-results-screen.ts +0 -469
  157. package/src/runtime/migrations/vbundle-builder.ts +0 -1382
  158. package/src/runtime/migrations/vbundle-import-analyzer.ts +0 -405
  159. package/src/runtime/migrations/vbundle-import-policy.ts +0 -241
  160. package/src/runtime/migrations/vbundle-importer.ts +0 -826
  161. package/src/runtime/migrations/vbundle-metadata-merge.ts +0 -113
  162. package/src/runtime/migrations/vbundle-streaming-importer.ts +0 -2844
  163. package/src/runtime/migrations/vbundle-streaming-validator.ts +0 -426
  164. package/src/runtime/migrations/vbundle-tar-stream.ts +0 -244
  165. package/src/runtime/migrations/vbundle-validator.ts +0 -724
  166. package/src/runtime/routes/__tests__/migration-cadet-metadata-reconcile.test.ts +0 -227
  167. package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +0 -54
  168. package/src/runtime/routes/__tests__/migration-import-allowed-hosts-env.test.ts +0 -70
  169. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +0 -257
  170. package/src/runtime/routes/background-wake-routes.ts +0 -387
  171. package/src/runtime/routes/migration-routes.ts +0 -2584
  172. package/src/tools/network/__tests__/cloud-search-proxy.test.ts +0 -282
  173. package/src/tools/network/cloud-search-proxy.ts +0 -211
  174. package/src/tts/__tests__/cadet-provider.test.ts +0 -253
  175. package/src/tts/providers/cadet-provider.ts +0 -244
  176. package/src/types/tar-stream.d.ts +0 -66
@@ -1,612 +0,0 @@
1
- /**
2
- * Shared transport methods for managed and runtime migration APIs.
3
- *
4
- * Provides typed functions for each migration endpoint, usable by
5
- * client web views (macOS/iOS WKWebView), the gateway, or any
6
- * TypeScript consumer that needs to call migration APIs.
7
- *
8
- * Two target APIs:
9
- *
10
- * Runtime (local daemon):
11
- * POST /v1/migrations/validate
12
- * POST /v1/migrations/export
13
- * POST /v1/migrations/import-preflight
14
- * POST /v1/migrations/import
15
- *
16
- * Managed (platform/Django):
17
- * POST /v1/migrations/validate/
18
- * POST /v1/migrations/export/
19
- * POST /v1/migrations/import-preflight/
20
- * POST /v1/migrations/import/
21
- * GET /v1/migrations/export/{job_id}/status/
22
- * GET /v1/migrations/import/{job_id}/status/
23
- *
24
- * All methods accept a `fetchFn` parameter for testability (defaults to
25
- * the global `fetch`). Auth headers are passed via `TransportConfig`.
26
- */
27
-
28
- import { z } from "zod";
29
-
30
- export type MigrationTarget = "runtime" | "managed";
31
-
32
- export interface TransportConfig {
33
- /** Base URL of the target API (e.g. "https://cloud.mycadet.ai"). */
34
- baseURL: string;
35
- /** Which API surface to target. Managed endpoints use trailing slashes. */
36
- target: MigrationTarget;
37
- /** Authorization header value (e.g. "Bearer <jwt>" or session token). */
38
- authHeader?: string;
39
- /** Header name for auth. Defaults to "Authorization" for runtime, "X-Session-Token" for managed. */
40
- authHeaderName?: string;
41
- /**
42
- * Additional headers to include with every request.
43
- * Merged after Content-Type but before auth-header injection,
44
- * so an explicit auth header from the transport always wins
45
- * over a same-named entry in defaultHeaders.
46
- */
47
- defaultHeaders?: Record<string, string>;
48
- /** Custom fetch implementation for testing or environments without global fetch. */
49
- fetchFn?: typeof fetch;
50
- }
51
-
52
- export interface ValidationError {
53
- code: string;
54
- message: string;
55
- path?: string;
56
- }
57
-
58
- interface ManifestFileEntry {
59
- path: string;
60
- sha256: string;
61
- size_bytes: number;
62
- }
63
-
64
- interface ManifestAssistantInfo {
65
- id: string;
66
- name: string;
67
- runtime_version: string;
68
- }
69
-
70
- interface ManifestOrigin {
71
- mode: "managed" | "self-hosted-remote" | "self-hosted-local";
72
- platform_version?: string;
73
- hostname?: string;
74
- }
75
-
76
- interface ManifestCompatibility {
77
- min_runtime_version: string;
78
- max_runtime_version: string | null;
79
- }
80
-
81
- interface ManifestExportOptions {
82
- include_logs: boolean;
83
- include_browser_state: boolean;
84
- include_memory_vectors: boolean;
85
- }
86
-
87
- export interface Manifest {
88
- schema_version: number;
89
- bundle_id: string;
90
- created_at: string;
91
- assistant: ManifestAssistantInfo;
92
- origin: ManifestOrigin;
93
- compatibility: ManifestCompatibility;
94
- contents: ManifestFileEntry[];
95
- checksum: string;
96
- secrets_redacted: boolean;
97
- export_options: ManifestExportOptions;
98
- }
99
-
100
- export interface ValidateSuccessResponse {
101
- is_valid: true;
102
- errors: ValidationError[];
103
- manifest: Manifest;
104
- }
105
-
106
- export interface ValidateFailureResponse {
107
- is_valid: false;
108
- errors: ValidationError[];
109
- }
110
-
111
- export type ValidateResponse =
112
- | ValidateSuccessResponse
113
- | ValidateFailureResponse;
114
-
115
- /** Runtime export returns the binary archive directly. */
116
- export interface ExportRuntimeResult {
117
- ok: true;
118
- archive: ArrayBuffer;
119
- filename: string;
120
- schemaVersion: number;
121
- checksum: string;
122
- }
123
-
124
- /** Managed export initiates an async job and returns a job ID. */
125
- export interface ExportManagedResult {
126
- ok: true;
127
- jobId: string;
128
- status: string;
129
- }
130
-
131
- type ExportResult = ExportRuntimeResult | ExportManagedResult;
132
-
133
- export interface ImportPreflightFileReport {
134
- path: string;
135
- action: "create" | "overwrite" | "unchanged" | "skip";
136
- bundle_size: number;
137
- current_size: number | null;
138
- bundle_sha256: string;
139
- current_sha256: string | null;
140
- }
141
-
142
- export interface ImportPreflightConflict {
143
- code: string;
144
- message: string;
145
- path?: string;
146
- }
147
-
148
- export interface ImportPreflightSuccessResponse {
149
- can_import: true;
150
- summary: {
151
- total_files: number;
152
- files_to_create: number;
153
- files_to_overwrite: number;
154
- files_unchanged: number;
155
- files_to_skip: number;
156
- };
157
- files: ImportPreflightFileReport[];
158
- conflicts: ImportPreflightConflict[];
159
- manifest: Manifest;
160
- }
161
-
162
- export interface ImportPreflightValidationFailedResponse {
163
- can_import: false;
164
- validation: {
165
- is_valid: false;
166
- errors: ValidationError[];
167
- };
168
- }
169
-
170
- export interface ImportPreflightConflictResponse {
171
- can_import: false;
172
- summary: {
173
- total_files: number;
174
- files_to_create: number;
175
- files_to_overwrite: number;
176
- files_unchanged: number;
177
- files_to_skip: number;
178
- };
179
- files: ImportPreflightFileReport[];
180
- conflicts: ImportPreflightConflict[];
181
- manifest: Manifest;
182
- }
183
-
184
- export type ImportPreflightResponse =
185
- | ImportPreflightSuccessResponse
186
- | ImportPreflightValidationFailedResponse
187
- | ImportPreflightConflictResponse;
188
-
189
- export interface ImportedFileReport {
190
- path: string;
191
- disk_path: string;
192
- action: "created" | "overwritten" | "skipped";
193
- size: number;
194
- sha256: string;
195
- backup_path: string | null;
196
- }
197
-
198
- export interface ImportCommitSuccessResponse {
199
- success: true;
200
- summary: {
201
- total_files: number;
202
- files_created: number;
203
- files_overwritten: number;
204
- files_skipped: number;
205
- backups_created: number;
206
- };
207
- files: ImportedFileReport[];
208
- manifest: Manifest;
209
- warnings: string[];
210
- credentialsImported?: {
211
- total: number;
212
- succeeded: number;
213
- failed: number;
214
- failedAccounts: string[];
215
- skippedPlatform?: number;
216
- };
217
- }
218
-
219
- export interface ImportCommitFailureResponse {
220
- success: false;
221
- reason: "validation_failed" | "extraction_failed" | "write_failed";
222
- errors?: ValidationError[];
223
- message?: string;
224
- partial_report?: unknown;
225
- }
226
-
227
- export type ImportCommitResponse =
228
- | ImportCommitSuccessResponse
229
- | ImportCommitFailureResponse;
230
-
231
- export interface JobStatusPending {
232
- status: "pending" | "processing";
233
- jobId: string;
234
- progress?: number;
235
- }
236
-
237
- export interface JobStatusComplete {
238
- status: "complete";
239
- jobId: string;
240
- downloadUrl?: string;
241
- result?: unknown;
242
- }
243
-
244
- export interface JobStatusFailed {
245
- status: "failed";
246
- jobId: string;
247
- error: string;
248
- }
249
-
250
- export type JobStatusResponse =
251
- | JobStatusPending
252
- | JobStatusComplete
253
- | JobStatusFailed;
254
-
255
- export class MigrationTransportError extends Error {
256
- readonly statusCode: number;
257
- readonly responseBody: string;
258
-
259
- constructor(message: string, statusCode: number, responseBody: string) {
260
- super(message);
261
- this.name = "MigrationTransportError";
262
- this.statusCode = statusCode;
263
- this.responseBody = responseBody;
264
- }
265
- }
266
-
267
- function resolveFetch(config: TransportConfig): typeof fetch {
268
- return config.fetchFn ?? globalThis.fetch;
269
- }
270
-
271
- function buildURL(config: TransportConfig, path: string): string {
272
- const base = config.baseURL.replace(/\/+$/, "");
273
- const trailingSlash = config.target === "managed" ? "/" : "";
274
- return `${base}/v1/migrations/${path}${trailingSlash}`;
275
- }
276
-
277
- function buildHeaders(
278
- config: TransportConfig,
279
- contentType?: string,
280
- ): Record<string, string> {
281
- const headers: Record<string, string> = {};
282
- const headerKeysByLowerName = new Map<string, string>();
283
-
284
- const setHeader = (headerName: string, headerValue: string): void => {
285
- const lowerName = headerName.toLowerCase();
286
- const existingHeaderName = headerKeysByLowerName.get(lowerName);
287
- if (existingHeaderName && existingHeaderName !== headerName) {
288
- delete headers[existingHeaderName];
289
- }
290
- headerKeysByLowerName.set(lowerName, headerName);
291
- headers[headerName] = headerValue;
292
- };
293
-
294
- if (contentType) {
295
- setHeader("Content-Type", contentType);
296
- }
297
-
298
- // Merge defaultHeaders after Content-Type but before auth injection
299
- if (config.defaultHeaders) {
300
- for (const [headerName, headerValue] of Object.entries(
301
- config.defaultHeaders,
302
- )) {
303
- setHeader(headerName, headerValue);
304
- }
305
- }
306
-
307
- // Auth header is applied last so it always wins over defaultHeaders
308
- if (config.authHeader) {
309
- const headerName =
310
- config.authHeaderName ??
311
- (config.target === "managed" ? "X-Session-Token" : "Authorization");
312
- setHeader(headerName, config.authHeader);
313
- }
314
-
315
- return headers;
316
- }
317
-
318
- async function assertOk(response: Response, context: string): Promise<void> {
319
- if (!response.ok) {
320
- const body = await response.text().catch(() => "<unreadable>");
321
- throw new MigrationTransportError(
322
- `${context}: HTTP ${response.status}`,
323
- response.status,
324
- body,
325
- );
326
- }
327
- }
328
-
329
- /**
330
- * Validate a .vbundle archive.
331
- *
332
- * Sends the archive as binary body and returns structured validation results.
333
- */
334
- export async function validateBundle(
335
- config: TransportConfig,
336
- fileData: ArrayBuffer,
337
- ): Promise<ValidateResponse> {
338
- const doFetch = resolveFetch(config);
339
- const url = buildURL(config, "validate");
340
-
341
- const response = await doFetch(url, {
342
- method: "POST",
343
- headers: buildHeaders(config, "application/octet-stream"),
344
- body: fileData,
345
- });
346
-
347
- await assertOk(response, "validate");
348
- return (await response.json()) as ValidateResponse;
349
- }
350
-
351
- /**
352
- * Export assistant data as a .vbundle archive.
353
- *
354
- * Runtime target: returns the binary archive directly.
355
- * Managed target: initiates an async export job and returns the job ID.
356
- */
357
- export async function exportBundle(
358
- config: TransportConfig,
359
- options?: { description?: string },
360
- ): Promise<ExportResult> {
361
- const doFetch = resolveFetch(config);
362
- const url = buildURL(config, "export");
363
-
364
- const body = options?.description
365
- ? JSON.stringify({ description: options.description })
366
- : undefined;
367
-
368
- const contentType = body ? "application/json" : undefined;
369
-
370
- const response = await doFetch(url, {
371
- method: "POST",
372
- headers: buildHeaders(config, contentType),
373
- ...(body ? { body } : {}),
374
- });
375
-
376
- await assertOk(response, "export");
377
-
378
- if (config.target === "managed") {
379
- const json = (await response.json()) as {
380
- job_id: string;
381
- status: string;
382
- };
383
- return {
384
- ok: true,
385
- jobId: json.job_id,
386
- status: json.status,
387
- } as ExportManagedResult;
388
- }
389
-
390
- // Runtime returns the binary archive. The legacy
391
- // `X-Vbundle-Manifest-Sha256` response header name is preserved for
392
- // cross-version client compat — its value is now sourced from the
393
- // renamed manifest `checksum` field.
394
- const archive = await response.arrayBuffer();
395
- const schemaVersionHeader =
396
- response.headers.get("X-Vbundle-Schema-Version") ?? "";
397
- const parsedSchemaVersion = Number.parseInt(schemaVersionHeader, 10);
398
- return {
399
- ok: true,
400
- archive,
401
- filename:
402
- response.headers
403
- .get("Content-Disposition")
404
- ?.match(/filename="?(.+?)"?$/)?.[1] ?? "export.vbundle",
405
- schemaVersion: Number.isFinite(parsedSchemaVersion)
406
- ? parsedSchemaVersion
407
- : 0,
408
- checksum: response.headers.get("X-Vbundle-Manifest-Sha256") ?? "",
409
- } as ExportRuntimeResult;
410
- }
411
-
412
- /**
413
- * Dry-run import analysis of a .vbundle archive.
414
- *
415
- * Returns a detailed report of what would change if the bundle were imported,
416
- * without modifying any data on disk.
417
- */
418
- export async function importPreflight(
419
- config: TransportConfig,
420
- fileData: ArrayBuffer,
421
- ): Promise<ImportPreflightResponse> {
422
- const doFetch = resolveFetch(config);
423
- const url = buildURL(config, "import-preflight");
424
-
425
- const response = await doFetch(url, {
426
- method: "POST",
427
- headers: buildHeaders(config, "application/octet-stream"),
428
- body: fileData,
429
- });
430
-
431
- await assertOk(response, "import-preflight");
432
- return (await response.json()) as ImportPreflightResponse;
433
- }
434
-
435
- /**
436
- * Commit a .vbundle archive import.
437
- *
438
- * This is a destructive operation that writes bundle files to their
439
- * target locations. For managed targets, this may initiate an async
440
- * import job.
441
- */
442
- export async function importCommit(
443
- config: TransportConfig,
444
- fileData: ArrayBuffer,
445
- ): Promise<ImportCommitResponse> {
446
- const doFetch = resolveFetch(config);
447
- const url = buildURL(config, "import");
448
-
449
- const response = await doFetch(url, {
450
- method: "POST",
451
- headers: buildHeaders(config, "application/octet-stream"),
452
- body: fileData,
453
- });
454
-
455
- // The import endpoint can return non-2xx for server errors but
456
- // also returns 200 with success: false for validation/write failures.
457
- // We only throw on non-2xx status codes.
458
- if (response.status >= 500) {
459
- const body = await response.text().catch(() => "<unreadable>");
460
- throw new MigrationTransportError(
461
- `import: HTTP ${response.status}`,
462
- response.status,
463
- body,
464
- );
465
- }
466
-
467
- // 400-level errors are also transport failures
468
- if (response.status >= 400 && response.status < 500) {
469
- const body = await response.text().catch(() => "<unreadable>");
470
- throw new MigrationTransportError(
471
- `import: HTTP ${response.status}`,
472
- response.status,
473
- body,
474
- );
475
- }
476
-
477
- return (await response.json()) as ImportCommitResponse;
478
- }
479
-
480
- /**
481
- * Poll the status of a cloud export job.
482
- *
483
- * Only applicable to managed targets. Runtime exports are synchronous
484
- * and do not require status polling.
485
- */
486
- export async function pollExportStatus(
487
- config: TransportConfig,
488
- jobId: string,
489
- ): Promise<JobStatusResponse> {
490
- return fetchJobStatus(config, "export", jobId);
491
- }
492
-
493
- /**
494
- * Poll the status of a cloud import job.
495
- *
496
- * Only applicable to managed targets. Runtime imports are synchronous
497
- * and do not require status polling.
498
- */
499
- export async function pollImportStatus(
500
- config: TransportConfig,
501
- jobId: string,
502
- ): Promise<JobStatusResponse> {
503
- return fetchJobStatus(config, "import", jobId);
504
- }
505
-
506
- const jobStatusWireSchema = z.object({
507
- status: z.enum(["pending", "processing", "complete", "failed"]),
508
- job_id: z.string().optional(),
509
- download_url: z.string().optional(),
510
- progress: z.number().optional(),
511
- error: z.string().optional(),
512
- result: z.unknown().optional(),
513
- });
514
-
515
- function jobStatusFromWire(
516
- wire: z.infer<typeof jobStatusWireSchema>,
517
- fallbackJobId: string,
518
- ): JobStatusResponse {
519
- const jobId = wire.job_id ?? fallbackJobId;
520
- if (wire.status === "complete") {
521
- return {
522
- status: "complete",
523
- jobId,
524
- downloadUrl: wire.download_url,
525
- result: wire.result,
526
- };
527
- }
528
- if (wire.status === "failed") {
529
- return {
530
- status: "failed",
531
- jobId,
532
- error: wire.error ?? "unknown export error",
533
- };
534
- }
535
- return { status: wire.status, jobId, progress: wire.progress };
536
- }
537
-
538
- async function fetchJobStatus(
539
- config: TransportConfig,
540
- kind: "export" | "import",
541
- jobId: string,
542
- ): Promise<JobStatusResponse> {
543
- if (config.target !== "managed") {
544
- throw new Error(
545
- `poll${kind === "export" ? "Export" : "Import"}Status is only supported for managed targets`,
546
- );
547
- }
548
-
549
- const doFetch = resolveFetch(config);
550
- const base = config.baseURL.replace(/\/+$/, "");
551
- const url = `${base}/v1/migrations/${kind}/${encodeURIComponent(
552
- jobId,
553
- )}/status/`;
554
-
555
- const response = await doFetch(url, {
556
- method: "GET",
557
- headers: buildHeaders(config),
558
- });
559
-
560
- await assertOk(response, `${kind} status (job ${jobId})`);
561
- const parsed = jobStatusWireSchema.safeParse(await response.json());
562
- if (!parsed.success) {
563
- throw new MigrationTransportError(
564
- `${kind} status (job ${jobId}): malformed response`,
565
- response.status,
566
- "",
567
- );
568
- }
569
- return jobStatusFromWire(parsed.data, jobId);
570
- }
571
-
572
- interface PollOptions {
573
- /** Polling interval in milliseconds. Defaults to 2000. */
574
- intervalMs?: number;
575
- /** Maximum number of polls before giving up. Defaults to 60. */
576
- maxAttempts?: number;
577
- /** Callback invoked on each poll with the latest status. */
578
- onProgress?: (status: JobStatusResponse) => void;
579
- }
580
-
581
- /**
582
- * Poll a cloud job until it reaches a terminal state (complete or failed).
583
- *
584
- * Returns the final status response. Throws if maxAttempts is exceeded.
585
- */
586
- export async function pollUntilComplete(
587
- config: TransportConfig,
588
- jobType: "export" | "import",
589
- jobId: string,
590
- options?: PollOptions,
591
- ): Promise<JobStatusComplete | JobStatusFailed> {
592
- const intervalMs = options?.intervalMs ?? 2000;
593
- const maxAttempts = options?.maxAttempts ?? 60;
594
- const pollFn = jobType === "export" ? pollExportStatus : pollImportStatus;
595
-
596
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
597
- const status = await pollFn(config, jobId);
598
- options?.onProgress?.(status);
599
-
600
- if (status.status === "complete" || status.status === "failed") {
601
- return status;
602
- }
603
-
604
- await new Promise((resolve) => setTimeout(resolve, intervalMs));
605
- }
606
-
607
- throw new MigrationTransportError(
608
- `${jobType} job ${jobId} did not complete within ${maxAttempts} polls`,
609
- 0,
610
- "",
611
- );
612
- }