@morphllm/morphsdk 0.2.93 → 0.2.95

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 (135) hide show
  1. package/dist/chunk-2AMEQAO2.js +46 -0
  2. package/dist/chunk-2AMEQAO2.js.map +1 -0
  3. package/dist/{chunk-EI4UKP24.js → chunk-2HMEZZKK.js} +2 -2
  4. package/dist/{chunk-EI4UKP24.js.map → chunk-2HMEZZKK.js.map} +1 -1
  5. package/dist/chunk-2VERUKO2.js +177 -0
  6. package/dist/chunk-2VERUKO2.js.map +1 -0
  7. package/dist/{chunk-VHOWYK66.js → chunk-43LQLGP6.js} +23 -33
  8. package/dist/chunk-43LQLGP6.js.map +1 -0
  9. package/dist/{chunk-LMUZ3NGC.js → chunk-73RV6EXR.js} +2 -2
  10. package/dist/{chunk-PBLPZ6AU.js → chunk-7D6TXC7X.js} +2 -2
  11. package/dist/{chunk-GU6DACME.js → chunk-O7LDZA52.js} +2 -2
  12. package/dist/{chunk-5QIWYEHJ.js → chunk-PE4KGDA6.js} +1 -8
  13. package/dist/chunk-PE4KGDA6.js.map +1 -0
  14. package/dist/{chunk-SQN4DUQS.js → chunk-Q6Y4R236.js} +26 -2
  15. package/dist/chunk-Q6Y4R236.js.map +1 -0
  16. package/dist/{chunk-PUGIOVSP.js → chunk-QAT5UVPX.js} +2 -2
  17. package/dist/{chunk-MIIJWDOQ.js → chunk-QJP62BXH.js} +166 -71
  18. package/dist/chunk-QJP62BXH.js.map +1 -0
  19. package/dist/{chunk-EYGBUH2R.js → chunk-R7IQWNSA.js} +8 -8
  20. package/dist/chunk-R7IQWNSA.js.map +1 -0
  21. package/dist/chunk-SI2CKRKJ.js +389 -0
  22. package/dist/chunk-SI2CKRKJ.js.map +1 -0
  23. package/dist/{chunk-4WLGDYWQ.js → chunk-TSENDJQI.js} +6 -6
  24. package/dist/chunk-TSENDJQI.js.map +1 -0
  25. package/dist/{chunk-IUG2FHNN.js → chunk-XH7P7HVT.js} +1 -8
  26. package/dist/chunk-XH7P7HVT.js.map +1 -0
  27. package/dist/{chunk-FNLNDMIX.js → chunk-YZ5NCWO2.js} +6 -6
  28. package/dist/chunk-YZ5NCWO2.js.map +1 -0
  29. package/dist/{chunk-IJ54DTJ3.js → chunk-ZYTAKEBW.js} +13 -13
  30. package/dist/client.cjs +770 -110
  31. package/dist/client.cjs.map +1 -1
  32. package/dist/client.d.ts +2 -0
  33. package/dist/client.js +16 -13
  34. package/dist/index.cjs +770 -110
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.ts +2 -0
  37. package/dist/index.js +16 -13
  38. package/dist/tools/browser/anthropic.cjs +58 -23
  39. package/dist/tools/browser/anthropic.cjs.map +1 -1
  40. package/dist/tools/browser/anthropic.js +7 -4
  41. package/dist/tools/browser/core.cjs +750 -70
  42. package/dist/tools/browser/core.cjs.map +1 -1
  43. package/dist/tools/browser/core.d.ts +30 -24
  44. package/dist/tools/browser/core.js +5 -2
  45. package/dist/tools/browser/errors.cjs +208 -0
  46. package/dist/tools/browser/errors.cjs.map +1 -0
  47. package/dist/tools/browser/errors.d.ts +158 -0
  48. package/dist/tools/browser/errors.js +22 -0
  49. package/dist/tools/browser/errors.js.map +1 -0
  50. package/dist/tools/browser/index.cjs +783 -85
  51. package/dist/tools/browser/index.cjs.map +1 -1
  52. package/dist/tools/browser/index.d.ts +5 -2
  53. package/dist/tools/browser/index.js +32 -9
  54. package/dist/tools/browser/index.js.map +1 -1
  55. package/dist/tools/browser/live.cjs +25 -1
  56. package/dist/tools/browser/live.cjs.map +1 -1
  57. package/dist/tools/browser/live.js +1 -1
  58. package/dist/tools/browser/openai.cjs +58 -23
  59. package/dist/tools/browser/openai.cjs.map +1 -1
  60. package/dist/tools/browser/openai.js +7 -4
  61. package/dist/tools/browser/profiles/core.cjs +670 -0
  62. package/dist/tools/browser/profiles/core.cjs.map +1 -0
  63. package/dist/tools/browser/profiles/core.d.ts +187 -0
  64. package/dist/tools/browser/profiles/core.js +29 -0
  65. package/dist/tools/browser/profiles/core.js.map +1 -0
  66. package/dist/tools/browser/profiles/index.cjs +670 -0
  67. package/dist/tools/browser/profiles/index.cjs.map +1 -0
  68. package/dist/tools/browser/profiles/index.d.ts +4 -0
  69. package/dist/tools/browser/profiles/index.js +29 -0
  70. package/dist/tools/browser/profiles/index.js.map +1 -0
  71. package/dist/tools/browser/profiles/types.cjs +74 -0
  72. package/dist/tools/browser/profiles/types.cjs.map +1 -0
  73. package/dist/tools/browser/profiles/types.d.ts +195 -0
  74. package/dist/tools/browser/profiles/types.js +16 -0
  75. package/dist/tools/browser/profiles/types.js.map +1 -0
  76. package/dist/tools/browser/prompts.cjs +1 -1
  77. package/dist/tools/browser/prompts.cjs.map +1 -1
  78. package/dist/tools/browser/prompts.d.ts +1 -1
  79. package/dist/tools/browser/prompts.js +1 -1
  80. package/dist/tools/browser/types.cjs.map +1 -1
  81. package/dist/tools/browser/types.d.ts +55 -51
  82. package/dist/tools/browser/vercel.cjs +60 -25
  83. package/dist/tools/browser/vercel.cjs.map +1 -1
  84. package/dist/tools/browser/vercel.d.ts +1 -1
  85. package/dist/tools/browser/vercel.js +7 -4
  86. package/dist/tools/fastapply/anthropic.cjs +0 -7
  87. package/dist/tools/fastapply/anthropic.cjs.map +1 -1
  88. package/dist/tools/fastapply/anthropic.js +1 -1
  89. package/dist/tools/fastapply/index.cjs +0 -14
  90. package/dist/tools/fastapply/index.cjs.map +1 -1
  91. package/dist/tools/fastapply/index.js +5 -5
  92. package/dist/tools/fastapply/openai.cjs +0 -7
  93. package/dist/tools/fastapply/openai.cjs.map +1 -1
  94. package/dist/tools/fastapply/openai.js +1 -1
  95. package/dist/tools/index.cjs +0 -14
  96. package/dist/tools/index.cjs.map +1 -1
  97. package/dist/tools/index.js +5 -5
  98. package/dist/tools/warp_grep/agent/runner.cjs +18 -98
  99. package/dist/tools/warp_grep/agent/runner.cjs.map +1 -1
  100. package/dist/tools/warp_grep/agent/runner.js +2 -3
  101. package/dist/tools/warp_grep/anthropic.cjs +18 -98
  102. package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
  103. package/dist/tools/warp_grep/anthropic.js +8 -9
  104. package/dist/tools/warp_grep/client.cjs +18 -98
  105. package/dist/tools/warp_grep/client.cjs.map +1 -1
  106. package/dist/tools/warp_grep/client.js +5 -6
  107. package/dist/tools/warp_grep/gemini.cjs +18 -98
  108. package/dist/tools/warp_grep/gemini.cjs.map +1 -1
  109. package/dist/tools/warp_grep/gemini.js +7 -8
  110. package/dist/tools/warp_grep/gemini.js.map +1 -1
  111. package/dist/tools/warp_grep/harness.js +10 -10
  112. package/dist/tools/warp_grep/index.cjs +18 -98
  113. package/dist/tools/warp_grep/index.cjs.map +1 -1
  114. package/dist/tools/warp_grep/index.js +8 -9
  115. package/dist/tools/warp_grep/openai.cjs +18 -98
  116. package/dist/tools/warp_grep/openai.cjs.map +1 -1
  117. package/dist/tools/warp_grep/openai.js +8 -9
  118. package/dist/tools/warp_grep/vercel.cjs +18 -98
  119. package/dist/tools/warp_grep/vercel.cjs.map +1 -1
  120. package/dist/tools/warp_grep/vercel.js +8 -9
  121. package/dist/{vercel-CsnNSdze.d.ts → vercel-CVF27qFK.d.ts} +10 -10
  122. package/package.json +7 -2
  123. package/dist/chunk-4WLGDYWQ.js.map +0 -1
  124. package/dist/chunk-5QIWYEHJ.js.map +0 -1
  125. package/dist/chunk-EYGBUH2R.js.map +0 -1
  126. package/dist/chunk-FNLNDMIX.js.map +0 -1
  127. package/dist/chunk-IUG2FHNN.js.map +0 -1
  128. package/dist/chunk-MIIJWDOQ.js.map +0 -1
  129. package/dist/chunk-SQN4DUQS.js.map +0 -1
  130. package/dist/chunk-VHOWYK66.js.map +0 -1
  131. /package/dist/{chunk-LMUZ3NGC.js.map → chunk-73RV6EXR.js.map} +0 -0
  132. /package/dist/{chunk-PBLPZ6AU.js.map → chunk-7D6TXC7X.js.map} +0 -0
  133. /package/dist/{chunk-GU6DACME.js.map → chunk-O7LDZA52.js.map} +0 -0
  134. /package/dist/{chunk-PUGIOVSP.js.map → chunk-QAT5UVPX.js.map} +0 -0
  135. /package/dist/{chunk-IJ54DTJ3.js.map → chunk-ZYTAKEBW.js.map} +0 -0
@@ -0,0 +1,670 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // tools/browser/profiles/index.ts
21
+ var profiles_exports = {};
22
+ __export(profiles_exports, {
23
+ ProfilesClient: () => ProfilesClient,
24
+ createProfile: () => createProfile,
25
+ deleteProfile: () => deleteProfile,
26
+ getProfile: () => getProfile,
27
+ getProfileState: () => getProfileState,
28
+ listProfiles: () => listProfiles,
29
+ listRepos: () => listRepos,
30
+ saveProfileSession: () => saveProfileSession,
31
+ startProfileSession: () => startProfileSession,
32
+ updateProfile: () => updateProfile
33
+ });
34
+ module.exports = __toCommonJS(profiles_exports);
35
+
36
+ // tools/utils/resilience.ts
37
+ var DEFAULT_RETRY_CONFIG = {
38
+ maxRetries: 3,
39
+ initialDelay: 1e3,
40
+ maxDelay: 3e4,
41
+ backoffMultiplier: 2,
42
+ retryableErrors: ["ECONNREFUSED", "ETIMEDOUT", "ENOTFOUND"]
43
+ };
44
+ async function fetchWithRetry(url, options, retryConfig = {}) {
45
+ const {
46
+ maxRetries = DEFAULT_RETRY_CONFIG.maxRetries,
47
+ initialDelay = DEFAULT_RETRY_CONFIG.initialDelay,
48
+ maxDelay = DEFAULT_RETRY_CONFIG.maxDelay,
49
+ backoffMultiplier = DEFAULT_RETRY_CONFIG.backoffMultiplier,
50
+ retryableErrors = DEFAULT_RETRY_CONFIG.retryableErrors,
51
+ onRetry
52
+ } = retryConfig;
53
+ let lastError = null;
54
+ let delay = initialDelay;
55
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
56
+ try {
57
+ const response = await fetch(url, options);
58
+ if (response.status === 429 || response.status === 503) {
59
+ if (attempt < maxRetries) {
60
+ const retryAfter = response.headers.get("Retry-After");
61
+ const waitTime = retryAfter ? parseInt(retryAfter) * 1e3 : Math.min(delay, maxDelay);
62
+ const error = new Error(`HTTP ${response.status}: Retrying after ${waitTime}ms`);
63
+ if (onRetry) {
64
+ onRetry(attempt + 1, error);
65
+ }
66
+ await sleep(waitTime);
67
+ delay *= backoffMultiplier;
68
+ continue;
69
+ }
70
+ }
71
+ return response;
72
+ } catch (error) {
73
+ lastError = error;
74
+ const isRetryable = retryableErrors.some(
75
+ (errType) => lastError?.message?.includes(errType)
76
+ );
77
+ if (!isRetryable || attempt === maxRetries) {
78
+ throw lastError;
79
+ }
80
+ const waitTime = Math.min(delay, maxDelay);
81
+ if (onRetry) {
82
+ onRetry(attempt + 1, lastError);
83
+ }
84
+ await sleep(waitTime);
85
+ delay *= backoffMultiplier;
86
+ }
87
+ }
88
+ throw lastError || new Error("Max retries exceeded");
89
+ }
90
+ function sleep(ms) {
91
+ return new Promise((resolve) => setTimeout(resolve, ms));
92
+ }
93
+
94
+ // tools/browser/errors.ts
95
+ var MorphError = class extends Error {
96
+ /** Error code for programmatic handling */
97
+ code;
98
+ /** Original cause of the error, if any */
99
+ cause;
100
+ constructor(message, code, cause) {
101
+ super(message);
102
+ this.name = "MorphError";
103
+ this.code = code;
104
+ this.cause = cause;
105
+ if (Error.captureStackTrace) {
106
+ Error.captureStackTrace(this, this.constructor);
107
+ }
108
+ }
109
+ /**
110
+ * Returns a JSON representation of the error for logging.
111
+ */
112
+ toJSON() {
113
+ return {
114
+ name: this.name,
115
+ message: this.message,
116
+ code: this.code,
117
+ cause: this.cause?.message
118
+ };
119
+ }
120
+ };
121
+ var MorphValidationError = class extends MorphError {
122
+ /** The field that failed validation */
123
+ field;
124
+ constructor(message, field) {
125
+ super(message, "validation_error");
126
+ this.name = "MorphValidationError";
127
+ this.field = field;
128
+ }
129
+ toJSON() {
130
+ return {
131
+ ...super.toJSON(),
132
+ field: this.field
133
+ };
134
+ }
135
+ };
136
+ var MorphAPIError = class extends MorphError {
137
+ /** HTTP status code */
138
+ statusCode;
139
+ /** Request ID for debugging (if available) */
140
+ requestId;
141
+ /** Raw response body */
142
+ rawResponse;
143
+ constructor(message, code, statusCode, options) {
144
+ super(message, code, options?.cause);
145
+ this.name = "MorphAPIError";
146
+ this.statusCode = statusCode;
147
+ this.requestId = options?.requestId;
148
+ this.rawResponse = options?.rawResponse;
149
+ }
150
+ toJSON() {
151
+ return {
152
+ ...super.toJSON(),
153
+ statusCode: this.statusCode,
154
+ requestId: this.requestId
155
+ };
156
+ }
157
+ };
158
+ var MorphAuthenticationError = class extends MorphAPIError {
159
+ constructor(message = "Authentication required. Please provide a valid API key.") {
160
+ super(message, "authentication_required", 401);
161
+ this.name = "MorphAuthenticationError";
162
+ }
163
+ };
164
+ var MorphRateLimitError = class extends MorphAPIError {
165
+ /** When the rate limit resets (Unix timestamp) */
166
+ resetAt;
167
+ /** Number of seconds until reset */
168
+ retryAfter;
169
+ constructor(message = "Rate limit exceeded. Please retry later.", options) {
170
+ super(message, "rate_limit_exceeded", 429, { requestId: options?.requestId });
171
+ this.name = "MorphRateLimitError";
172
+ this.resetAt = options?.resetAt;
173
+ this.retryAfter = options?.retryAfter;
174
+ }
175
+ toJSON() {
176
+ return {
177
+ ...super.toJSON(),
178
+ resetAt: this.resetAt,
179
+ retryAfter: this.retryAfter
180
+ };
181
+ }
182
+ };
183
+ var MorphNotFoundError = class extends MorphAPIError {
184
+ /** The type of resource that was not found */
185
+ resourceType;
186
+ /** The ID of the resource that was not found */
187
+ resourceId;
188
+ constructor(resourceType, resourceId) {
189
+ const message = resourceId ? `${resourceType} '${resourceId}' not found` : `${resourceType} not found`;
190
+ super(message, "resource_not_found", 404);
191
+ this.name = "MorphNotFoundError";
192
+ this.resourceType = resourceType;
193
+ this.resourceId = resourceId;
194
+ }
195
+ toJSON() {
196
+ return {
197
+ ...super.toJSON(),
198
+ resourceType: this.resourceType,
199
+ resourceId: this.resourceId
200
+ };
201
+ }
202
+ };
203
+ var MorphProfileLimitError = class extends MorphAPIError {
204
+ /** Current number of profiles */
205
+ currentCount;
206
+ /** Maximum allowed profiles for the plan */
207
+ maxAllowed;
208
+ constructor(message = "Profile limit exceeded for your plan.", options) {
209
+ super(message, "profile_limit_exceeded", 403, { requestId: options?.requestId });
210
+ this.name = "MorphProfileLimitError";
211
+ this.currentCount = options?.currentCount;
212
+ this.maxAllowed = options?.maxAllowed;
213
+ }
214
+ toJSON() {
215
+ return {
216
+ ...super.toJSON(),
217
+ currentCount: this.currentCount,
218
+ maxAllowed: this.maxAllowed
219
+ };
220
+ }
221
+ };
222
+ function parseAPIError(statusCode, responseText, requestId) {
223
+ let errorData = {};
224
+ try {
225
+ errorData = JSON.parse(responseText);
226
+ } catch {
227
+ }
228
+ const message = errorData.detail || errorData.message || responseText || "Unknown error";
229
+ const code = errorData.code;
230
+ switch (statusCode) {
231
+ case 401:
232
+ return new MorphAuthenticationError(message);
233
+ case 403:
234
+ if (code === "profile_limit_exceeded" || message.toLowerCase().includes("limit")) {
235
+ return new MorphProfileLimitError(message, { requestId });
236
+ }
237
+ return new MorphAPIError(message, "insufficient_permissions", statusCode, { requestId, rawResponse: responseText });
238
+ case 404:
239
+ if (message.toLowerCase().includes("profile")) {
240
+ return new MorphNotFoundError("Profile", void 0);
241
+ }
242
+ if (message.toLowerCase().includes("session")) {
243
+ return new MorphNotFoundError("Session", void 0);
244
+ }
245
+ return new MorphAPIError(message, "resource_not_found", statusCode, { requestId, rawResponse: responseText });
246
+ case 429:
247
+ return new MorphRateLimitError(message, { requestId });
248
+ case 422:
249
+ return new MorphAPIError(message, "validation_error", statusCode, { requestId, rawResponse: responseText });
250
+ case 500:
251
+ case 502:
252
+ case 503:
253
+ case 504:
254
+ return new MorphAPIError(message, "service_unavailable", statusCode, { requestId, rawResponse: responseText });
255
+ default:
256
+ return new MorphAPIError(message, "network_error", statusCode, { requestId, rawResponse: responseText });
257
+ }
258
+ }
259
+
260
+ // tools/browser/profiles/types.ts
261
+ function transformProfile(api) {
262
+ return {
263
+ id: api.id,
264
+ name: api.name,
265
+ repoId: api.repo_id,
266
+ cookieDomains: api.cookie_domains,
267
+ lastUsedAt: api.last_used_at,
268
+ createdAt: api.created_at,
269
+ updatedAt: api.updated_at
270
+ };
271
+ }
272
+ function transformCreateInput(input) {
273
+ return {
274
+ name: input.name,
275
+ repo_id: input.repoId
276
+ };
277
+ }
278
+ function transformSession(api) {
279
+ return {
280
+ sessionId: api.session_id,
281
+ debugUrl: api.debug_url || ""
282
+ };
283
+ }
284
+ function transformSaveInput(input) {
285
+ return {
286
+ session_id: input.sessionId,
287
+ profile_id: input.profileId
288
+ };
289
+ }
290
+ function transformStateResponse(api) {
291
+ return {
292
+ profileId: api.profile_id,
293
+ stateUrl: api.state_url,
294
+ expiresIn: api.expires_in
295
+ };
296
+ }
297
+
298
+ // tools/browser/profiles/core.ts
299
+ var DEFAULT_API_URL = process.env.MORPH_ENVIRONMENT === "DEV" ? "http://localhost:8000" : "https://browser.morphllm.com";
300
+ var ProfilesClient = class {
301
+ config;
302
+ constructor(config) {
303
+ this.config = config;
304
+ }
305
+ /**
306
+ * Create a new browser profile and immediately start a live session.
307
+ *
308
+ * @param input - Profile creation parameters
309
+ * @returns Profile setup handle with live URL + save()
310
+ * @throws {MorphValidationError} If input validation fails
311
+ * @throws {MorphProfileLimitError} If profile limit is exceeded
312
+ * @throws {MorphAuthenticationError} If API key is missing or invalid
313
+ *
314
+ * @example
315
+ * ```typescript
316
+ * const setup = await morph.browser.profiles.createProfile({
317
+ * name: 'LinkedIn Production',
318
+ * repoId: 'owner/repo'
319
+ * });
320
+ * console.log(setup.session.debugUrl);
321
+ * await setup.save();
322
+ * ```
323
+ */
324
+ async createProfile(input) {
325
+ return createProfile(input, this.config);
326
+ }
327
+ /**
328
+ * List all profiles for the authenticated user.
329
+ *
330
+ * @param repoId - Optional repository ID to filter by
331
+ * @returns Array of profiles
332
+ *
333
+ * @example
334
+ * ```typescript
335
+ * // List all profiles
336
+ * const allProfiles = await morph.browser.profiles.listProfiles();
337
+ *
338
+ * // List profiles for a specific repo
339
+ * const repoProfiles = await morph.browser.profiles.listProfiles('owner/repo');
340
+ * ```
341
+ */
342
+ async listProfiles(repoId) {
343
+ return listProfiles(this.config, repoId);
344
+ }
345
+ /**
346
+ * Get a profile by ID with convenience methods.
347
+ *
348
+ * @param id - Profile ID
349
+ * @returns Profile with attached methods
350
+ * @throws {MorphNotFoundError} If profile is not found
351
+ *
352
+ * @example
353
+ * ```typescript
354
+ * const profile = await morph.browser.profiles.getProfile('profile-id');
355
+ * const state = await profile.getState();
356
+ * await profile.delete();
357
+ * ```
358
+ */
359
+ async getProfile(id) {
360
+ return getProfile(id, this.config);
361
+ }
362
+ /**
363
+ * Update a profile by opening a live session (no rename).
364
+ *
365
+ * @param id - Profile ID
366
+ * @returns Profile setup handle with live URL + save()
367
+ */
368
+ async updateProfile(id) {
369
+ return updateProfile(id, this.config);
370
+ }
371
+ /**
372
+ * Delete a profile.
373
+ *
374
+ * @param id - Profile ID
375
+ * @throws {MorphNotFoundError} If profile is not found
376
+ */
377
+ async deleteProfile(id) {
378
+ return deleteProfile(id, this.config);
379
+ }
380
+ /**
381
+ * Start a browser session for profile setup.
382
+ *
383
+ * Returns a live URL where the user can sign into accounts.
384
+ * After signing in, call `saveSession` to persist the state.
385
+ *
386
+ * @param input - Optional session parameters
387
+ * @returns Session with debug URL
388
+ *
389
+ * @example
390
+ * ```typescript
391
+ * const session = await morph.browser.profiles.startSession();
392
+ * console.log('Sign in at:', session.debugUrl);
393
+ * // Open debugUrl in browser, user signs in...
394
+ * await morph.browser.profiles.saveSession(session.sessionId, profile.id);
395
+ * ```
396
+ */
397
+ async startSession(input) {
398
+ return startProfileSession(this.config, input);
399
+ }
400
+ /**
401
+ * Save browser state from a session to a profile.
402
+ *
403
+ * Call this after the user is done signing into accounts.
404
+ * Extracts cookies, localStorage, and sessionStorage.
405
+ *
406
+ * @param sessionId - Browser session ID from startSession
407
+ * @param profileId - Profile ID to save state to
408
+ * @returns Updated profile with cookie domains
409
+ */
410
+ async saveSession(sessionId, profileId) {
411
+ return saveProfileSession({ sessionId, profileId }, this.config);
412
+ }
413
+ /**
414
+ * List available repo IDs (discovery).
415
+ *
416
+ * @returns Repo summaries with profile counts
417
+ */
418
+ async listRepos() {
419
+ return listRepos(this.config);
420
+ }
421
+ /**
422
+ * Get the presigned URL for a profile's state.
423
+ *
424
+ * Use this to download the raw state JSON for debugging
425
+ * or to restore state manually.
426
+ *
427
+ * @param profileId - Profile ID
428
+ * @returns State URL with expiry information
429
+ */
430
+ async getProfileState(profileId) {
431
+ return getProfileState(profileId, this.config);
432
+ }
433
+ };
434
+ function validateCreateInput(input) {
435
+ if (!input.name || typeof input.name !== "string") {
436
+ throw new MorphValidationError("name is required", "name");
437
+ }
438
+ const trimmedName = input.name.trim();
439
+ if (trimmedName.length === 0) {
440
+ throw new MorphValidationError("name cannot be empty", "name");
441
+ }
442
+ if (trimmedName.length > 100) {
443
+ throw new MorphValidationError("name must be 100 characters or less", "name");
444
+ }
445
+ if (!input.repoId || typeof input.repoId !== "string") {
446
+ throw new MorphValidationError("repoId is required", "repoId");
447
+ }
448
+ if (input.repoId.trim().length === 0) {
449
+ throw new MorphValidationError("repoId cannot be empty", "repoId");
450
+ }
451
+ }
452
+ function validateId(id, fieldName) {
453
+ if (!id || typeof id !== "string") {
454
+ throw new MorphValidationError(`${fieldName} is required`, fieldName);
455
+ }
456
+ if (id.trim().length === 0) {
457
+ throw new MorphValidationError(`${fieldName} cannot be empty`, fieldName);
458
+ }
459
+ }
460
+ async function createProfile(input, config = {}) {
461
+ validateCreateInput(input);
462
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
463
+ const headers = buildHeaders(config);
464
+ const response = await fetchWithRetry(
465
+ `${apiUrl}/profiles`,
466
+ {
467
+ method: "POST",
468
+ headers,
469
+ body: JSON.stringify(transformCreateInput(input))
470
+ },
471
+ config.retryConfig
472
+ );
473
+ if (!response.ok) {
474
+ const errorText = await response.text().catch(() => response.statusText);
475
+ const requestId = response.headers.get("x-request-id") || void 0;
476
+ throw parseAPIError(response.status, errorText, requestId);
477
+ }
478
+ const apiProfile = await response.json();
479
+ const profile = transformProfile(apiProfile);
480
+ const session = await startProfileSession(config, { profileId: profile.id });
481
+ return buildProfileSetup(profile, session, config);
482
+ }
483
+ async function listProfiles(config = {}, repoId) {
484
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
485
+ const headers = buildHeaders(config);
486
+ const url = repoId ? `${apiUrl}/profiles?repo_id=${encodeURIComponent(repoId)}` : `${apiUrl}/profiles`;
487
+ const response = await fetchWithRetry(
488
+ url,
489
+ { method: "GET", headers },
490
+ config.retryConfig
491
+ );
492
+ if (!response.ok) {
493
+ const errorText = await response.text().catch(() => response.statusText);
494
+ const requestId = response.headers.get("x-request-id") || void 0;
495
+ throw parseAPIError(response.status, errorText, requestId);
496
+ }
497
+ const data = await response.json();
498
+ return data.profiles.map(transformProfile);
499
+ }
500
+ async function getProfile(id, config = {}) {
501
+ validateId(id, "id");
502
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
503
+ const headers = buildHeaders(config);
504
+ const response = await fetchWithRetry(
505
+ `${apiUrl}/profiles/${encodeURIComponent(id)}`,
506
+ { method: "GET", headers },
507
+ config.retryConfig
508
+ );
509
+ if (!response.ok) {
510
+ const errorText = await response.text().catch(() => response.statusText);
511
+ const requestId = response.headers.get("x-request-id") || void 0;
512
+ throw parseAPIError(response.status, errorText, requestId);
513
+ }
514
+ const apiProfile = await response.json();
515
+ const profile = transformProfile(apiProfile);
516
+ return {
517
+ ...profile,
518
+ getState: () => getProfileState(id, config),
519
+ delete: () => deleteProfile(id, config)
520
+ };
521
+ }
522
+ async function updateProfile(id, config = {}) {
523
+ validateId(id, "id");
524
+ const profile = await fetchProfile(id, config);
525
+ const session = await startProfileSession(config, { profileId: profile.id });
526
+ return buildProfileSetup(profile, session, config);
527
+ }
528
+ async function deleteProfile(id, config = {}) {
529
+ validateId(id, "id");
530
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
531
+ const headers = buildHeaders(config);
532
+ const response = await fetchWithRetry(
533
+ `${apiUrl}/profiles/${encodeURIComponent(id)}`,
534
+ { method: "DELETE", headers },
535
+ config.retryConfig
536
+ );
537
+ if (!response.ok) {
538
+ const errorText = await response.text().catch(() => response.statusText);
539
+ const requestId = response.headers.get("x-request-id") || void 0;
540
+ throw parseAPIError(response.status, errorText, requestId);
541
+ }
542
+ }
543
+ async function startProfileSession(config = {}, input) {
544
+ if (!config.apiKey) {
545
+ throw new MorphAuthenticationError();
546
+ }
547
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
548
+ const headers = buildHeaders(config);
549
+ const body = input?.profileId ? { profile_id: input.profileId } : {};
550
+ const response = await fetchWithRetry(
551
+ `${apiUrl}/profiles/session/start`,
552
+ {
553
+ method: "POST",
554
+ headers,
555
+ body: JSON.stringify(body)
556
+ },
557
+ config.retryConfig
558
+ );
559
+ if (!response.ok) {
560
+ const errorText = await response.text().catch(() => response.statusText);
561
+ const requestId = response.headers.get("x-request-id") || void 0;
562
+ throw parseAPIError(response.status, errorText, requestId);
563
+ }
564
+ const apiSession = await response.json();
565
+ return transformSession(apiSession);
566
+ }
567
+ async function saveProfileSession(input, config = {}) {
568
+ validateId(input.sessionId, "sessionId");
569
+ validateId(input.profileId, "profileId");
570
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
571
+ const headers = buildHeaders(config);
572
+ const response = await fetchWithRetry(
573
+ `${apiUrl}/profiles/session/save`,
574
+ {
575
+ method: "POST",
576
+ headers,
577
+ body: JSON.stringify(transformSaveInput(input))
578
+ },
579
+ config.retryConfig
580
+ );
581
+ if (!response.ok) {
582
+ const errorText = await response.text().catch(() => response.statusText);
583
+ const requestId = response.headers.get("x-request-id") || void 0;
584
+ throw parseAPIError(response.status, errorText, requestId);
585
+ }
586
+ const apiProfile = await response.json();
587
+ return transformProfile(apiProfile);
588
+ }
589
+ async function listRepos(config = {}) {
590
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
591
+ const headers = buildHeaders(config);
592
+ const response = await fetchWithRetry(
593
+ `${apiUrl}/repos`,
594
+ { method: "GET", headers },
595
+ config.retryConfig
596
+ );
597
+ if (!response.ok) {
598
+ const errorText = await response.text().catch(() => response.statusText);
599
+ const requestId = response.headers.get("x-request-id") || void 0;
600
+ throw parseAPIError(response.status, errorText, requestId);
601
+ }
602
+ const data = await response.json();
603
+ const repos = Array.isArray(data?.repos) ? data.repos : [];
604
+ return repos.map((repo) => ({
605
+ repoId: repo.repo_id,
606
+ repoFullName: repo.repo_full_name,
607
+ profileCount: repo.profile_count ?? 0
608
+ }));
609
+ }
610
+ async function getProfileState(profileId, config = {}) {
611
+ validateId(profileId, "profileId");
612
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
613
+ const headers = buildHeaders(config);
614
+ const response = await fetchWithRetry(
615
+ `${apiUrl}/profiles/${encodeURIComponent(profileId)}/state`,
616
+ { method: "GET", headers },
617
+ config.retryConfig
618
+ );
619
+ if (!response.ok) {
620
+ const errorText = await response.text().catch(() => response.statusText);
621
+ const requestId = response.headers.get("x-request-id") || void 0;
622
+ throw parseAPIError(response.status, errorText, requestId);
623
+ }
624
+ const apiState = await response.json();
625
+ return transformStateResponse(apiState);
626
+ }
627
+ function buildHeaders(config) {
628
+ const headers = { "Content-Type": "application/json" };
629
+ if (config.apiKey) {
630
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
631
+ }
632
+ return headers;
633
+ }
634
+ async function fetchProfile(id, config) {
635
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
636
+ const headers = buildHeaders(config);
637
+ const response = await fetchWithRetry(
638
+ `${apiUrl}/profiles/${encodeURIComponent(id)}`,
639
+ { method: "GET", headers },
640
+ config.retryConfig
641
+ );
642
+ if (!response.ok) {
643
+ const errorText = await response.text().catch(() => response.statusText);
644
+ const requestId = response.headers.get("x-request-id") || void 0;
645
+ throw parseAPIError(response.status, errorText, requestId);
646
+ }
647
+ const apiProfile = await response.json();
648
+ return transformProfile(apiProfile);
649
+ }
650
+ function buildProfileSetup(profile, session, config) {
651
+ return {
652
+ profile,
653
+ session,
654
+ save: () => saveProfileSession({ sessionId: session.sessionId, profileId: profile.id }, config)
655
+ };
656
+ }
657
+ // Annotate the CommonJS export names for ESM import in node:
658
+ 0 && (module.exports = {
659
+ ProfilesClient,
660
+ createProfile,
661
+ deleteProfile,
662
+ getProfile,
663
+ getProfileState,
664
+ listProfiles,
665
+ listRepos,
666
+ saveProfileSession,
667
+ startProfileSession,
668
+ updateProfile
669
+ });
670
+ //# sourceMappingURL=index.cjs.map