@morphllm/morphsdk 0.2.92 → 0.2.94

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 (86) hide show
  1. package/dist/{chunk-IJ54DTJ3.js → chunk-4WO7PJNT.js} +11 -11
  2. package/dist/{chunk-EYGBUH2R.js → chunk-AV6YV2MH.js} +2 -2
  3. package/dist/{chunk-LMUZ3NGC.js → chunk-BVVDDTI7.js} +2 -2
  4. package/dist/chunk-ESRZJRTQ.js +359 -0
  5. package/dist/chunk-ESRZJRTQ.js.map +1 -0
  6. package/dist/{chunk-GU6DACME.js → chunk-FIA6LBW2.js} +2 -2
  7. package/dist/{chunk-4WLGDYWQ.js → chunk-FMWNVTJJ.js} +2 -2
  8. package/dist/{chunk-PBLPZ6AU.js → chunk-IH3KN4AT.js} +2 -2
  9. package/dist/{chunk-MIIJWDOQ.js → chunk-M7GFXRKL.js} +13 -3
  10. package/dist/chunk-M7GFXRKL.js.map +1 -0
  11. package/dist/{chunk-4KMBU6T3.js → chunk-R7WN43L2.js} +4 -4
  12. package/dist/{chunk-PUGIOVSP.js → chunk-TXYCM4NP.js} +2 -2
  13. package/dist/chunk-UJ7LVT5G.js +177 -0
  14. package/dist/chunk-UJ7LVT5G.js.map +1 -0
  15. package/dist/{chunk-FNLNDMIX.js → chunk-WSQMWVSD.js} +2 -2
  16. package/dist/chunk-YJ354BA2.js +46 -0
  17. package/dist/chunk-YJ354BA2.js.map +1 -0
  18. package/dist/client.cjs +546 -4
  19. package/dist/client.cjs.map +1 -1
  20. package/dist/client.d.ts +2 -0
  21. package/dist/client.js +12 -9
  22. package/dist/index.cjs +546 -4
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.ts +2 -0
  25. package/dist/index.js +12 -9
  26. package/dist/tools/browser/anthropic.cjs +5 -1
  27. package/dist/tools/browser/anthropic.cjs.map +1 -1
  28. package/dist/tools/browser/anthropic.js +5 -2
  29. package/dist/tools/browser/core.cjs +544 -2
  30. package/dist/tools/browser/core.cjs.map +1 -1
  31. package/dist/tools/browser/core.d.ts +6 -0
  32. package/dist/tools/browser/core.js +4 -1
  33. package/dist/tools/browser/errors.cjs +208 -0
  34. package/dist/tools/browser/errors.cjs.map +1 -0
  35. package/dist/tools/browser/errors.d.ts +158 -0
  36. package/dist/tools/browser/errors.js +22 -0
  37. package/dist/tools/browser/errors.js.map +1 -0
  38. package/dist/tools/browser/index.cjs +562 -2
  39. package/dist/tools/browser/index.cjs.map +1 -1
  40. package/dist/tools/browser/index.d.ts +3 -0
  41. package/dist/tools/browser/index.js +27 -4
  42. package/dist/tools/browser/index.js.map +1 -1
  43. package/dist/tools/browser/openai.cjs +5 -1
  44. package/dist/tools/browser/openai.cjs.map +1 -1
  45. package/dist/tools/browser/openai.js +5 -2
  46. package/dist/tools/browser/profiles/core.cjs +639 -0
  47. package/dist/tools/browser/profiles/core.cjs.map +1 -0
  48. package/dist/tools/browser/profiles/core.d.ts +179 -0
  49. package/dist/tools/browser/profiles/core.js +27 -0
  50. package/dist/tools/browser/profiles/core.js.map +1 -0
  51. package/dist/tools/browser/profiles/index.cjs +639 -0
  52. package/dist/tools/browser/profiles/index.cjs.map +1 -0
  53. package/dist/tools/browser/profiles/index.d.ts +4 -0
  54. package/dist/tools/browser/profiles/index.js +27 -0
  55. package/dist/tools/browser/profiles/index.js.map +1 -0
  56. package/dist/tools/browser/profiles/types.cjs +74 -0
  57. package/dist/tools/browser/profiles/types.cjs.map +1 -0
  58. package/dist/tools/browser/profiles/types.d.ts +176 -0
  59. package/dist/tools/browser/profiles/types.js +16 -0
  60. package/dist/tools/browser/profiles/types.js.map +1 -0
  61. package/dist/tools/browser/types.cjs.map +1 -1
  62. package/dist/tools/browser/types.d.ts +2 -0
  63. package/dist/tools/browser/vercel.cjs +5 -1
  64. package/dist/tools/browser/vercel.cjs.map +1 -1
  65. package/dist/tools/browser/vercel.js +5 -2
  66. package/dist/tools/fastapply/index.js +3 -3
  67. package/dist/tools/index.js +3 -3
  68. package/dist/tools/warp_grep/anthropic.js +4 -4
  69. package/dist/tools/warp_grep/client.js +3 -3
  70. package/dist/tools/warp_grep/gemini.js +3 -3
  71. package/dist/tools/warp_grep/harness.js +2 -2
  72. package/dist/tools/warp_grep/index.js +3 -3
  73. package/dist/tools/warp_grep/openai.js +4 -4
  74. package/dist/tools/warp_grep/providers/local.js +2 -2
  75. package/dist/tools/warp_grep/vercel.js +4 -4
  76. package/package.json +7 -2
  77. package/dist/chunk-MIIJWDOQ.js.map +0 -1
  78. /package/dist/{chunk-IJ54DTJ3.js.map → chunk-4WO7PJNT.js.map} +0 -0
  79. /package/dist/{chunk-EYGBUH2R.js.map → chunk-AV6YV2MH.js.map} +0 -0
  80. /package/dist/{chunk-LMUZ3NGC.js.map → chunk-BVVDDTI7.js.map} +0 -0
  81. /package/dist/{chunk-GU6DACME.js.map → chunk-FIA6LBW2.js.map} +0 -0
  82. /package/dist/{chunk-4WLGDYWQ.js.map → chunk-FMWNVTJJ.js.map} +0 -0
  83. /package/dist/{chunk-PBLPZ6AU.js.map → chunk-IH3KN4AT.js.map} +0 -0
  84. /package/dist/{chunk-4KMBU6T3.js.map → chunk-R7WN43L2.js.map} +0 -0
  85. /package/dist/{chunk-PUGIOVSP.js.map → chunk-TXYCM4NP.js.map} +0 -0
  86. /package/dist/{chunk-FNLNDMIX.js.map → chunk-WSQMWVSD.js.map} +0 -0
@@ -24,6 +24,14 @@ __export(browser_exports, {
24
24
  BROWSER_TOOL_DESCRIPTION: () => BROWSER_TOOL_DESCRIPTION,
25
25
  BrowserClient: () => BrowserClient,
26
26
  LIVE_PRESETS: () => LIVE_PRESETS,
27
+ MorphAPIError: () => MorphAPIError,
28
+ MorphAuthenticationError: () => MorphAuthenticationError,
29
+ MorphError: () => MorphError,
30
+ MorphNotFoundError: () => MorphNotFoundError,
31
+ MorphProfileLimitError: () => MorphProfileLimitError,
32
+ MorphRateLimitError: () => MorphRateLimitError,
33
+ MorphValidationError: () => MorphValidationError,
34
+ ProfilesClient: () => ProfilesClient,
27
35
  anthropic: () => anthropic_exports,
28
36
  buildEmbedCode: () => buildEmbedCode,
29
37
  buildLiveIframe: () => buildLiveIframe,
@@ -36,6 +44,7 @@ __export(browser_exports, {
36
44
  getRecording: () => getRecording,
37
45
  getWebp: () => getWebp,
38
46
  openai: () => openai_exports,
47
+ parseAPIError: () => parseAPIError,
39
48
  vercel: () => vercel_exports,
40
49
  waitForRecording: () => waitForRecording
41
50
  });
@@ -191,6 +200,541 @@ function resolvePreset(optionsOrPreset) {
191
200
  return optionsOrPreset;
192
201
  }
193
202
 
203
+ // tools/browser/errors.ts
204
+ var MorphError = class extends Error {
205
+ /** Error code for programmatic handling */
206
+ code;
207
+ /** Original cause of the error, if any */
208
+ cause;
209
+ constructor(message, code, cause) {
210
+ super(message);
211
+ this.name = "MorphError";
212
+ this.code = code;
213
+ this.cause = cause;
214
+ if (Error.captureStackTrace) {
215
+ Error.captureStackTrace(this, this.constructor);
216
+ }
217
+ }
218
+ /**
219
+ * Returns a JSON representation of the error for logging.
220
+ */
221
+ toJSON() {
222
+ return {
223
+ name: this.name,
224
+ message: this.message,
225
+ code: this.code,
226
+ cause: this.cause?.message
227
+ };
228
+ }
229
+ };
230
+ var MorphValidationError = class extends MorphError {
231
+ /** The field that failed validation */
232
+ field;
233
+ constructor(message, field) {
234
+ super(message, "validation_error");
235
+ this.name = "MorphValidationError";
236
+ this.field = field;
237
+ }
238
+ toJSON() {
239
+ return {
240
+ ...super.toJSON(),
241
+ field: this.field
242
+ };
243
+ }
244
+ };
245
+ var MorphAPIError = class extends MorphError {
246
+ /** HTTP status code */
247
+ statusCode;
248
+ /** Request ID for debugging (if available) */
249
+ requestId;
250
+ /** Raw response body */
251
+ rawResponse;
252
+ constructor(message, code, statusCode, options) {
253
+ super(message, code, options?.cause);
254
+ this.name = "MorphAPIError";
255
+ this.statusCode = statusCode;
256
+ this.requestId = options?.requestId;
257
+ this.rawResponse = options?.rawResponse;
258
+ }
259
+ toJSON() {
260
+ return {
261
+ ...super.toJSON(),
262
+ statusCode: this.statusCode,
263
+ requestId: this.requestId
264
+ };
265
+ }
266
+ };
267
+ var MorphAuthenticationError = class extends MorphAPIError {
268
+ constructor(message = "Authentication required. Please provide a valid API key.") {
269
+ super(message, "authentication_required", 401);
270
+ this.name = "MorphAuthenticationError";
271
+ }
272
+ };
273
+ var MorphRateLimitError = class extends MorphAPIError {
274
+ /** When the rate limit resets (Unix timestamp) */
275
+ resetAt;
276
+ /** Number of seconds until reset */
277
+ retryAfter;
278
+ constructor(message = "Rate limit exceeded. Please retry later.", options) {
279
+ super(message, "rate_limit_exceeded", 429, { requestId: options?.requestId });
280
+ this.name = "MorphRateLimitError";
281
+ this.resetAt = options?.resetAt;
282
+ this.retryAfter = options?.retryAfter;
283
+ }
284
+ toJSON() {
285
+ return {
286
+ ...super.toJSON(),
287
+ resetAt: this.resetAt,
288
+ retryAfter: this.retryAfter
289
+ };
290
+ }
291
+ };
292
+ var MorphNotFoundError = class extends MorphAPIError {
293
+ /** The type of resource that was not found */
294
+ resourceType;
295
+ /** The ID of the resource that was not found */
296
+ resourceId;
297
+ constructor(resourceType, resourceId) {
298
+ const message = resourceId ? `${resourceType} '${resourceId}' not found` : `${resourceType} not found`;
299
+ super(message, "resource_not_found", 404);
300
+ this.name = "MorphNotFoundError";
301
+ this.resourceType = resourceType;
302
+ this.resourceId = resourceId;
303
+ }
304
+ toJSON() {
305
+ return {
306
+ ...super.toJSON(),
307
+ resourceType: this.resourceType,
308
+ resourceId: this.resourceId
309
+ };
310
+ }
311
+ };
312
+ var MorphProfileLimitError = class extends MorphAPIError {
313
+ /** Current number of profiles */
314
+ currentCount;
315
+ /** Maximum allowed profiles for the plan */
316
+ maxAllowed;
317
+ constructor(message = "Profile limit exceeded for your plan.", options) {
318
+ super(message, "profile_limit_exceeded", 403, { requestId: options?.requestId });
319
+ this.name = "MorphProfileLimitError";
320
+ this.currentCount = options?.currentCount;
321
+ this.maxAllowed = options?.maxAllowed;
322
+ }
323
+ toJSON() {
324
+ return {
325
+ ...super.toJSON(),
326
+ currentCount: this.currentCount,
327
+ maxAllowed: this.maxAllowed
328
+ };
329
+ }
330
+ };
331
+ function parseAPIError(statusCode, responseText, requestId) {
332
+ let errorData = {};
333
+ try {
334
+ errorData = JSON.parse(responseText);
335
+ } catch {
336
+ }
337
+ const message = errorData.detail || errorData.message || responseText || "Unknown error";
338
+ const code = errorData.code;
339
+ switch (statusCode) {
340
+ case 401:
341
+ return new MorphAuthenticationError(message);
342
+ case 403:
343
+ if (code === "profile_limit_exceeded" || message.toLowerCase().includes("limit")) {
344
+ return new MorphProfileLimitError(message, { requestId });
345
+ }
346
+ return new MorphAPIError(message, "insufficient_permissions", statusCode, { requestId, rawResponse: responseText });
347
+ case 404:
348
+ if (message.toLowerCase().includes("profile")) {
349
+ return new MorphNotFoundError("Profile", void 0);
350
+ }
351
+ if (message.toLowerCase().includes("session")) {
352
+ return new MorphNotFoundError("Session", void 0);
353
+ }
354
+ return new MorphAPIError(message, "resource_not_found", statusCode, { requestId, rawResponse: responseText });
355
+ case 429:
356
+ return new MorphRateLimitError(message, { requestId });
357
+ case 422:
358
+ return new MorphAPIError(message, "validation_error", statusCode, { requestId, rawResponse: responseText });
359
+ case 500:
360
+ case 502:
361
+ case 503:
362
+ case 504:
363
+ return new MorphAPIError(message, "service_unavailable", statusCode, { requestId, rawResponse: responseText });
364
+ default:
365
+ return new MorphAPIError(message, "network_error", statusCode, { requestId, rawResponse: responseText });
366
+ }
367
+ }
368
+
369
+ // tools/browser/profiles/types.ts
370
+ function transformProfile(api) {
371
+ return {
372
+ id: api.id,
373
+ name: api.name,
374
+ repoId: api.repo_id,
375
+ cookieDomains: api.cookie_domains,
376
+ lastUsedAt: api.last_used_at,
377
+ createdAt: api.created_at,
378
+ updatedAt: api.updated_at
379
+ };
380
+ }
381
+ function transformCreateInput(input) {
382
+ return {
383
+ name: input.name,
384
+ repo_id: input.repoId
385
+ };
386
+ }
387
+ function transformSession(api) {
388
+ return {
389
+ sessionId: api.session_id,
390
+ debugUrl: api.debug_url || api.debugUrl || ""
391
+ };
392
+ }
393
+ function transformSaveInput(input) {
394
+ return {
395
+ session_id: input.sessionId,
396
+ profile_id: input.profileId
397
+ };
398
+ }
399
+ function transformStateResponse(api) {
400
+ return {
401
+ profileId: api.profile_id,
402
+ stateUrl: api.state_url,
403
+ expiresIn: api.expires_in
404
+ };
405
+ }
406
+
407
+ // tools/browser/profiles/core.ts
408
+ var DEFAULT_API_URL = process.env.MORPH_ENVIRONMENT === "DEV" ? "http://localhost:8000" : "https://browser.morphllm.com";
409
+ var ProfilesClient = class {
410
+ config;
411
+ constructor(config) {
412
+ this.config = config;
413
+ }
414
+ /**
415
+ * Create a new browser profile.
416
+ *
417
+ * @param input - Profile creation parameters
418
+ * @returns The created profile
419
+ * @throws {MorphValidationError} If input validation fails
420
+ * @throws {MorphProfileLimitError} If profile limit is exceeded
421
+ * @throws {MorphAuthenticationError} If API key is missing or invalid
422
+ *
423
+ * @example
424
+ * ```typescript
425
+ * const profile = await morph.browser.profiles.createProfile({
426
+ * name: 'LinkedIn Production',
427
+ * repoId: 'repo-uuid-here'
428
+ * });
429
+ * ```
430
+ */
431
+ async createProfile(input) {
432
+ return createProfile(input, this.config);
433
+ }
434
+ /**
435
+ * List all profiles for the authenticated user.
436
+ *
437
+ * @param repoId - Optional repository ID to filter by
438
+ * @returns Array of profiles
439
+ *
440
+ * @example
441
+ * ```typescript
442
+ * // List all profiles
443
+ * const allProfiles = await morph.browser.profiles.listProfiles();
444
+ *
445
+ * // List profiles for a specific repo
446
+ * const repoProfiles = await morph.browser.profiles.listProfiles('repo-uuid');
447
+ * ```
448
+ */
449
+ async listProfiles(repoId) {
450
+ return listProfiles(this.config, repoId);
451
+ }
452
+ /**
453
+ * Get a profile by ID with convenience methods.
454
+ *
455
+ * @param id - Profile ID
456
+ * @returns Profile with attached methods
457
+ * @throws {MorphNotFoundError} If profile is not found
458
+ *
459
+ * @example
460
+ * ```typescript
461
+ * const profile = await morph.browser.profiles.getProfile('profile-id');
462
+ * const state = await profile.getState();
463
+ * await profile.delete();
464
+ * ```
465
+ */
466
+ async getProfile(id) {
467
+ return getProfile(id, this.config);
468
+ }
469
+ /**
470
+ * Update a profile's name.
471
+ *
472
+ * @param id - Profile ID
473
+ * @param input - Update parameters
474
+ * @returns Updated profile
475
+ */
476
+ async updateProfile(id, input) {
477
+ return updateProfile(id, input, this.config);
478
+ }
479
+ /**
480
+ * Delete a profile.
481
+ *
482
+ * @param id - Profile ID
483
+ * @throws {MorphNotFoundError} If profile is not found
484
+ */
485
+ async deleteProfile(id) {
486
+ return deleteProfile(id, this.config);
487
+ }
488
+ /**
489
+ * Start a browser session for profile setup.
490
+ *
491
+ * Returns a live URL where the user can sign into accounts.
492
+ * After signing in, call `saveSession` to persist the state.
493
+ *
494
+ * @param input - Optional session parameters
495
+ * @returns Session with debug URL
496
+ *
497
+ * @example
498
+ * ```typescript
499
+ * const session = await morph.browser.profiles.startSession();
500
+ * console.log('Sign in at:', session.debugUrl);
501
+ * // Open debugUrl in browser, user signs in...
502
+ * await morph.browser.profiles.saveSession(session.sessionId, profile.id);
503
+ * ```
504
+ */
505
+ async startSession(input) {
506
+ return startProfileSession(this.config, input);
507
+ }
508
+ /**
509
+ * Save browser state from a session to a profile.
510
+ *
511
+ * Call this after the user is done signing into accounts.
512
+ * Extracts cookies, localStorage, and sessionStorage.
513
+ *
514
+ * @param sessionId - Browser session ID from startSession
515
+ * @param profileId - Profile ID to save state to
516
+ * @returns Updated profile with cookie domains
517
+ */
518
+ async saveSession(sessionId, profileId) {
519
+ return saveProfileSession({ sessionId, profileId }, this.config);
520
+ }
521
+ /**
522
+ * Get the presigned URL for a profile's state.
523
+ *
524
+ * Use this to download the raw state JSON for debugging
525
+ * or to restore state manually.
526
+ *
527
+ * @param profileId - Profile ID
528
+ * @returns State URL with expiry information
529
+ */
530
+ async getProfileState(profileId) {
531
+ return getProfileState(profileId, this.config);
532
+ }
533
+ };
534
+ function validateCreateInput(input) {
535
+ if (!input.name || typeof input.name !== "string") {
536
+ throw new MorphValidationError("name is required", "name");
537
+ }
538
+ const trimmedName = input.name.trim();
539
+ if (trimmedName.length === 0) {
540
+ throw new MorphValidationError("name cannot be empty", "name");
541
+ }
542
+ if (trimmedName.length > 100) {
543
+ throw new MorphValidationError("name must be 100 characters or less", "name");
544
+ }
545
+ if (!input.repoId || typeof input.repoId !== "string") {
546
+ throw new MorphValidationError("repoId is required", "repoId");
547
+ }
548
+ if (input.repoId.trim().length === 0) {
549
+ throw new MorphValidationError("repoId cannot be empty", "repoId");
550
+ }
551
+ }
552
+ function validateId(id, fieldName) {
553
+ if (!id || typeof id !== "string") {
554
+ throw new MorphValidationError(`${fieldName} is required`, fieldName);
555
+ }
556
+ if (id.trim().length === 0) {
557
+ throw new MorphValidationError(`${fieldName} cannot be empty`, fieldName);
558
+ }
559
+ }
560
+ async function createProfile(input, config = {}) {
561
+ validateCreateInput(input);
562
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
563
+ const headers = buildHeaders(config);
564
+ const response = await fetchWithRetry(
565
+ `${apiUrl}/profiles`,
566
+ {
567
+ method: "POST",
568
+ headers,
569
+ body: JSON.stringify(transformCreateInput(input))
570
+ },
571
+ config.retryConfig
572
+ );
573
+ if (!response.ok) {
574
+ const errorText = await response.text().catch(() => response.statusText);
575
+ const requestId = response.headers.get("x-request-id") || void 0;
576
+ throw parseAPIError(response.status, errorText, requestId);
577
+ }
578
+ const apiProfile = await response.json();
579
+ return transformProfile(apiProfile);
580
+ }
581
+ async function listProfiles(config = {}, repoId) {
582
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
583
+ const headers = buildHeaders(config);
584
+ const url = repoId ? `${apiUrl}/profiles?repo_id=${encodeURIComponent(repoId)}` : `${apiUrl}/profiles`;
585
+ const response = await fetchWithRetry(
586
+ url,
587
+ { method: "GET", headers },
588
+ config.retryConfig
589
+ );
590
+ if (!response.ok) {
591
+ const errorText = await response.text().catch(() => response.statusText);
592
+ const requestId = response.headers.get("x-request-id") || void 0;
593
+ throw parseAPIError(response.status, errorText, requestId);
594
+ }
595
+ const data = await response.json();
596
+ return data.profiles.map(transformProfile);
597
+ }
598
+ async function getProfile(id, config = {}) {
599
+ validateId(id, "id");
600
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
601
+ const headers = buildHeaders(config);
602
+ const response = await fetchWithRetry(
603
+ `${apiUrl}/profiles/${encodeURIComponent(id)}`,
604
+ { method: "GET", headers },
605
+ config.retryConfig
606
+ );
607
+ if (!response.ok) {
608
+ const errorText = await response.text().catch(() => response.statusText);
609
+ const requestId = response.headers.get("x-request-id") || void 0;
610
+ throw parseAPIError(response.status, errorText, requestId);
611
+ }
612
+ const apiProfile = await response.json();
613
+ const profile = transformProfile(apiProfile);
614
+ return {
615
+ ...profile,
616
+ getState: () => getProfileState(id, config),
617
+ delete: () => deleteProfile(id, config)
618
+ };
619
+ }
620
+ async function updateProfile(id, input, config = {}) {
621
+ validateId(id, "id");
622
+ if (input.name !== void 0) {
623
+ if (typeof input.name !== "string") {
624
+ throw new MorphValidationError("name must be a string", "name");
625
+ }
626
+ if (input.name.trim().length === 0) {
627
+ throw new MorphValidationError("name cannot be empty", "name");
628
+ }
629
+ if (input.name.length > 100) {
630
+ throw new MorphValidationError("name must be 100 characters or less", "name");
631
+ }
632
+ }
633
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
634
+ const headers = buildHeaders(config);
635
+ const response = await fetchWithRetry(
636
+ `${apiUrl}/profiles/${encodeURIComponent(id)}`,
637
+ {
638
+ method: "PATCH",
639
+ headers,
640
+ body: JSON.stringify(input)
641
+ },
642
+ config.retryConfig
643
+ );
644
+ if (!response.ok) {
645
+ const errorText = await response.text().catch(() => response.statusText);
646
+ const requestId = response.headers.get("x-request-id") || void 0;
647
+ throw parseAPIError(response.status, errorText, requestId);
648
+ }
649
+ const apiProfile = await response.json();
650
+ return transformProfile(apiProfile);
651
+ }
652
+ async function deleteProfile(id, config = {}) {
653
+ validateId(id, "id");
654
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
655
+ const headers = buildHeaders(config);
656
+ const response = await fetchWithRetry(
657
+ `${apiUrl}/profiles/${encodeURIComponent(id)}`,
658
+ { method: "DELETE", headers },
659
+ config.retryConfig
660
+ );
661
+ if (!response.ok) {
662
+ const errorText = await response.text().catch(() => response.statusText);
663
+ const requestId = response.headers.get("x-request-id") || void 0;
664
+ throw parseAPIError(response.status, errorText, requestId);
665
+ }
666
+ }
667
+ async function startProfileSession(config = {}, input) {
668
+ if (!config.apiKey) {
669
+ throw new MorphAuthenticationError();
670
+ }
671
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
672
+ const headers = buildHeaders(config);
673
+ const body = input?.profileId ? { profile_id: input.profileId } : {};
674
+ const response = await fetchWithRetry(
675
+ `${apiUrl}/profiles/session/start`,
676
+ {
677
+ method: "POST",
678
+ headers,
679
+ body: JSON.stringify(body)
680
+ },
681
+ config.retryConfig
682
+ );
683
+ if (!response.ok) {
684
+ const errorText = await response.text().catch(() => response.statusText);
685
+ const requestId = response.headers.get("x-request-id") || void 0;
686
+ throw parseAPIError(response.status, errorText, requestId);
687
+ }
688
+ const apiSession = await response.json();
689
+ return transformSession(apiSession);
690
+ }
691
+ async function saveProfileSession(input, config = {}) {
692
+ validateId(input.sessionId, "sessionId");
693
+ validateId(input.profileId, "profileId");
694
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
695
+ const headers = buildHeaders(config);
696
+ const response = await fetchWithRetry(
697
+ `${apiUrl}/profiles/session/save`,
698
+ {
699
+ method: "POST",
700
+ headers,
701
+ body: JSON.stringify(transformSaveInput(input))
702
+ },
703
+ config.retryConfig
704
+ );
705
+ if (!response.ok) {
706
+ const errorText = await response.text().catch(() => response.statusText);
707
+ const requestId = response.headers.get("x-request-id") || void 0;
708
+ throw parseAPIError(response.status, errorText, requestId);
709
+ }
710
+ const apiProfile = await response.json();
711
+ return transformProfile(apiProfile);
712
+ }
713
+ async function getProfileState(profileId, config = {}) {
714
+ validateId(profileId, "profileId");
715
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
716
+ const headers = buildHeaders(config);
717
+ const response = await fetchWithRetry(
718
+ `${apiUrl}/profiles/${encodeURIComponent(profileId)}/state`,
719
+ { method: "GET", headers },
720
+ config.retryConfig
721
+ );
722
+ if (!response.ok) {
723
+ const errorText = await response.text().catch(() => response.statusText);
724
+ const requestId = response.headers.get("x-request-id") || void 0;
725
+ throw parseAPIError(response.status, errorText, requestId);
726
+ }
727
+ const apiState = await response.json();
728
+ return transformStateResponse(apiState);
729
+ }
730
+ function buildHeaders(config) {
731
+ const headers = { "Content-Type": "application/json" };
732
+ if (config.apiKey) {
733
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
734
+ }
735
+ return headers;
736
+ }
737
+
194
738
  // tools/browser/core.ts
195
739
  var DEFAULT_CONFIG = {
196
740
  apiUrl: process.env.MORPH_ENVIRONMENT === "DEV" ? "http://localhost:8000" : "https://browser.morphllm.com",
@@ -200,11 +744,16 @@ var DEFAULT_CONFIG = {
200
744
  };
201
745
  var BrowserClient = class {
202
746
  config;
747
+ /**
748
+ * Profile management - create and manage browser profiles for storing login state.
749
+ */
750
+ profiles;
203
751
  constructor(config = {}) {
204
752
  this.config = {
205
753
  ...DEFAULT_CONFIG,
206
754
  ...config
207
755
  };
756
+ this.profiles = new ProfilesClient(this.config);
208
757
  }
209
758
  /**
210
759
  * Execute a browser automation task
@@ -239,7 +788,8 @@ var BrowserClient = class {
239
788
  video_height: input.video_height ?? input.viewport_height ?? 720,
240
789
  allow_resizing: input.allow_resizing ?? false,
241
790
  structured_output: "schema" in input ? stringifyStructuredOutput(input.schema) : void 0,
242
- auth: input.auth
791
+ auth: input.auth,
792
+ profile_id: input.profile_id
243
793
  })
244
794
  });
245
795
  if (!response.ok) {
@@ -338,7 +888,8 @@ async function executeBrowserTask(input, config = {}) {
338
888
  video_height: input.video_height ?? input.viewport_height ?? 720,
339
889
  allow_resizing: input.allow_resizing ?? false,
340
890
  structured_output: input.structured_output,
341
- auth: input.auth
891
+ auth: input.auth,
892
+ profile_id: input.profile_id
342
893
  })
343
894
  },
344
895
  config.retryConfig
@@ -981,6 +1532,14 @@ var gemini_default = browserFunctionDeclaration;
981
1532
  BROWSER_TOOL_DESCRIPTION,
982
1533
  BrowserClient,
983
1534
  LIVE_PRESETS,
1535
+ MorphAPIError,
1536
+ MorphAuthenticationError,
1537
+ MorphError,
1538
+ MorphNotFoundError,
1539
+ MorphProfileLimitError,
1540
+ MorphRateLimitError,
1541
+ MorphValidationError,
1542
+ ProfilesClient,
984
1543
  anthropic,
985
1544
  buildEmbedCode,
986
1545
  buildLiveIframe,
@@ -993,6 +1552,7 @@ var gemini_default = browserFunctionDeclaration;
993
1552
  getRecording,
994
1553
  getWebp,
995
1554
  openai,
1555
+ parseAPIError,
996
1556
  vercel,
997
1557
  waitForRecording
998
1558
  });