effect-browserbase 0.2.0-beta.8 → 0.3.0-beta.10
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/README.md +277 -315
- package/dist/Browserbase-CaPKwEY9.mjs +544 -0
- package/dist/Browserbase-CaPKwEY9.mjs.map +1 -0
- package/dist/Browserbase.d.mts +110 -0
- package/dist/Browserbase.mjs +3 -0
- package/dist/BrowserbaseClient-CtAQ2rg4.d.mts +195 -0
- package/dist/BrowserbaseClient.d.mts +2 -0
- package/dist/BrowserbaseClient.mjs +190 -0
- package/dist/BrowserbaseClient.mjs.map +1 -0
- package/dist/BrowserbaseError-D1EOrLNc.d.mts +79 -0
- package/dist/BrowserbaseError.d.mts +2 -0
- package/dist/BrowserbaseError.mjs +101 -0
- package/dist/BrowserbaseError.mjs.map +1 -0
- package/dist/ContextLease.d.mts +42 -0
- package/dist/ContextLease.mjs +80 -0
- package/dist/ContextLease.mjs.map +1 -0
- package/dist/index.d.mts +5 -27
- package/dist/index.mjs +5 -26
- package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/dist/testing/index.d.mts +136 -0
- package/dist/testing/index.mjs +440 -0
- package/dist/testing/index.mjs.map +1 -0
- package/package.json +51 -121
- package/src/Browserbase.ts +729 -0
- package/src/BrowserbaseClient.ts +559 -0
- package/src/BrowserbaseError.ts +108 -0
- package/src/ContextLease.ts +118 -0
- package/src/index.ts +7 -0
- package/src/internal/captureConnection.ts +214 -0
- package/src/testing/BrowserbaseContract.ts +170 -0
- package/src/testing/TestBrowserbase.ts +509 -0
- package/src/testing/index.ts +7 -0
- package/dist/Account.d.mts +0 -32
- package/dist/Account.mjs +0 -36
- package/dist/Account.mjs.map +0 -1
- package/dist/Acquisition-BOABu_qJ.mjs +0 -244
- package/dist/Acquisition-BOABu_qJ.mjs.map +0 -1
- package/dist/Agents-CPaTOH_g.d.mts +0 -156
- package/dist/Agents.d.mts +0 -3
- package/dist/Agents.mjs +0 -292
- package/dist/Agents.mjs.map +0 -1
- package/dist/Allocation.d.mts +0 -97
- package/dist/Allocation.mjs +0 -27
- package/dist/Allocation.mjs.map +0 -1
- package/dist/Authorization-Ll5f_XNM.mjs +0 -12
- package/dist/Authorization-Ll5f_XNM.mjs.map +0 -1
- package/dist/Browser-ByrWJ0ss.mjs +0 -274
- package/dist/Browser-ByrWJ0ss.mjs.map +0 -1
- package/dist/Browser.d.mts +0 -83
- package/dist/Browser.mjs +0 -3
- package/dist/BrowserBinding.d.mts +0 -13
- package/dist/BrowserBinding.mjs +0 -31
- package/dist/BrowserBinding.mjs.map +0 -1
- package/dist/Certificates-D4NQmyeA.d.mts +0 -34
- package/dist/Certificates.d.mts +0 -3
- package/dist/Certificates.mjs +0 -85
- package/dist/Certificates.mjs.map +0 -1
- package/dist/Cleanup-DMTDBir8.d.mts +0 -23
- package/dist/Cleanup.d.mts +0 -3
- package/dist/Cleanup.mjs +0 -43
- package/dist/Cleanup.mjs.map +0 -1
- package/dist/Client-BEC4Q8ZS.mjs +0 -564
- package/dist/Client-BEC4Q8ZS.mjs.map +0 -1
- package/dist/Client-B_f6bBLT.d.mts +0 -52
- package/dist/Client.d.mts +0 -3
- package/dist/Client.mjs +0 -2
- package/dist/Connection-sxyxtwlk.mjs +0 -56
- package/dist/Connection-sxyxtwlk.mjs.map +0 -1
- package/dist/ContextCoordination.d.mts +0 -29
- package/dist/ContextCoordination.mjs +0 -94
- package/dist/ContextCoordination.mjs.map +0 -1
- package/dist/ContextWriter-CiEma24z.mjs +0 -204
- package/dist/ContextWriter-CiEma24z.mjs.map +0 -1
- package/dist/Contexts-DqdL7cyX.d.mts +0 -31
- package/dist/Contexts.d.mts +0 -3
- package/dist/Contexts.mjs +0 -97
- package/dist/Contexts.mjs.map +0 -1
- package/dist/Deadline-CrViaogr.mjs +0 -13
- package/dist/Deadline-CrViaogr.mjs.map +0 -1
- package/dist/Downloads-CX52GOFJ.d.mts +0 -43
- package/dist/Downloads.d.mts +0 -3
- package/dist/Downloads.mjs +0 -137
- package/dist/Downloads.mjs.map +0 -1
- package/dist/Errors.d.mts +0 -100
- package/dist/Errors.mjs +0 -194
- package/dist/Errors.mjs.map +0 -1
- package/dist/Extensions-BTUn9zhK.mjs +0 -231
- package/dist/Extensions-BTUn9zhK.mjs.map +0 -1
- package/dist/Extensions-DBXuVM1f.d.mts +0 -43
- package/dist/Extensions.d.mts +0 -3
- package/dist/Extensions.mjs +0 -2
- package/dist/Functions-CsKMMUuZ.d.mts +0 -226
- package/dist/Functions.d.mts +0 -3
- package/dist/Functions.mjs +0 -318
- package/dist/Functions.mjs.map +0 -1
- package/dist/Issued-DejqoMYL.mjs +0 -15
- package/dist/Issued-DejqoMYL.mjs.map +0 -1
- package/dist/Launch-cAdE2rrZ.mjs +0 -115
- package/dist/Launch-cAdE2rrZ.mjs.map +0 -1
- package/dist/Launch.d.mts +0 -127
- package/dist/Launch.mjs +0 -97
- package/dist/Launch.mjs.map +0 -1
- package/dist/PageFetch-CjAM_0DS.d.mts +0 -40
- package/dist/PageFetch.d.mts +0 -3
- package/dist/PageFetch.mjs +0 -59
- package/dist/PageFetch.mjs.map +0 -1
- package/dist/Projects-tm5bTDH0.d.mts +0 -38
- package/dist/Projects.d.mts +0 -3
- package/dist/Projects.mjs +0 -65
- package/dist/Projects.mjs.map +0 -1
- package/dist/Recordings-B9k5aODB.d.mts +0 -27
- package/dist/Recordings.d.mts +0 -3
- package/dist/Recordings.mjs +0 -144
- package/dist/Recordings.mjs.map +0 -1
- package/dist/References-DOH3Wu44.d.mts +0 -34
- package/dist/References.d.mts +0 -3
- package/dist/References.mjs +0 -33
- package/dist/References.mjs.map +0 -1
- package/dist/Replays-mV93WGtx.d.mts +0 -27
- package/dist/Replays.d.mts +0 -3
- package/dist/Replays.mjs +0 -107
- package/dist/Replays.mjs.map +0 -1
- package/dist/Resource-J7Kkk5mu.mjs +0 -54
- package/dist/Resource-J7Kkk5mu.mjs.map +0 -1
- package/dist/Search-B64e7g-h.d.mts +0 -37
- package/dist/Search.d.mts +0 -3
- package/dist/Search.mjs +0 -46
- package/dist/Search.mjs.map +0 -1
- package/dist/SessionData-5xYZDshJ.d.mts +0 -38
- package/dist/SessionData.d.mts +0 -3
- package/dist/SessionData.mjs +0 -48
- package/dist/SessionData.mjs.map +0 -1
- package/dist/Sessions-D2H5m6rF.mjs +0 -260
- package/dist/Sessions-D2H5m6rF.mjs.map +0 -1
- package/dist/Sessions-oJEUmZth.d.mts +0 -69
- package/dist/Sessions.d.mts +0 -4
- package/dist/Sessions.mjs +0 -3
- package/dist/Testing.d.mts +0 -119
- package/dist/Testing.mjs +0 -206
- package/dist/Testing.mjs.map +0 -1
- package/dist/TransferPolicy-DQ06i7SZ.mjs +0 -25
- package/dist/TransferPolicy-DQ06i7SZ.mjs.map +0 -1
- package/dist/Transfers-GVqzrDWl.d.mts +0 -89
- package/dist/Transfers.d.mts +0 -3
- package/dist/Transfers.mjs +0 -85
- package/dist/Transfers.mjs.map +0 -1
- package/dist/Uploads-C2_bACgv.d.mts +0 -28
- package/dist/Uploads.d.mts +0 -3
- package/dist/Uploads.mjs +0 -105
- package/dist/Uploads.mjs.map +0 -1
- package/dist/Webhooks-BoeRAxzG.d.mts +0 -59
- package/dist/Webhooks.d.mts +0 -3
- package/dist/Webhooks.mjs +0 -134
- package/dist/Webhooks.mjs.map +0 -1
- package/dist/WriterFacts-BBJRDZYY.d.mts +0 -54
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An in-memory Browserbase API for tests. It is the `HttpClient` the real `BrowserbaseClient` runs
|
|
3
|
+
* on, so the client and the provider above it run as they would against Browserbase, and nothing
|
|
4
|
+
* leaves the process. Sessions run until released, or until their timeout on the Effect `Clock`,
|
|
5
|
+
* so `TestClock` drives their end. A `Script` decides how creates, releases and session reads
|
|
6
|
+
* answer, in turn, so a test can lose a create, leave a release pending or fail status reads.
|
|
7
|
+
*
|
|
8
|
+
* It keeps sessions and stored contexts, and supplies synthetic Live View links: any other endpoint
|
|
9
|
+
* fails the test with a defect. It doesn't model quotas or billing, and a context is only a record,
|
|
10
|
+
* with no browser state. Every session hands out the script's `connectUrl`, such as the DevTools address
|
|
11
|
+
* of a local Chromium. Its ids are UUIDs, as Browserbase's are, and as Browserbase does, it refuses
|
|
12
|
+
* a session or context id of any other shape as invalid, where it answers an unknown one as not
|
|
13
|
+
* found.
|
|
14
|
+
*
|
|
15
|
+
* @category testing
|
|
16
|
+
* @since 0.3.0
|
|
17
|
+
*/
|
|
18
|
+
import {
|
|
19
|
+
Clock,
|
|
20
|
+
Context,
|
|
21
|
+
DateTime,
|
|
22
|
+
Effect,
|
|
23
|
+
Layer,
|
|
24
|
+
Option,
|
|
25
|
+
Predicate,
|
|
26
|
+
Redacted,
|
|
27
|
+
Schema,
|
|
28
|
+
} from "effect";
|
|
29
|
+
import {
|
|
30
|
+
HttpClient,
|
|
31
|
+
HttpClientError,
|
|
32
|
+
type HttpClientRequest,
|
|
33
|
+
HttpClientResponse,
|
|
34
|
+
} from "effect/http";
|
|
35
|
+
|
|
36
|
+
import {
|
|
37
|
+
type BrowserbaseClient,
|
|
38
|
+
layer as clientLayer,
|
|
39
|
+
type SessionOptions,
|
|
40
|
+
} from "../BrowserbaseClient.ts";
|
|
41
|
+
|
|
42
|
+
const Refusal = Schema.Int.check(Schema.isBetween({ minimum: 400, maximum: 599 }));
|
|
43
|
+
|
|
44
|
+
/** How a session create answers. */
|
|
45
|
+
export const Create = Schema.Union([
|
|
46
|
+
/** The session is made, and runs. */
|
|
47
|
+
Schema.TaggedStruct("Accept", {}),
|
|
48
|
+
/** Refused with `status`, and nothing is made. */
|
|
49
|
+
Schema.TaggedStruct("Reject", {
|
|
50
|
+
status: Refusal,
|
|
51
|
+
retryAfterSeconds: Schema.optional(Schema.Int),
|
|
52
|
+
}),
|
|
53
|
+
/** The session is made, but the answer holds only its id. */
|
|
54
|
+
Schema.TaggedStruct("Malformed", {}),
|
|
55
|
+
/**
|
|
56
|
+
* The session is made, but no answer arrives, and Browserbase lists it only `listedAfter`
|
|
57
|
+
* milliseconds later, as a search can trail what was made.
|
|
58
|
+
*/
|
|
59
|
+
Schema.TaggedStruct("Lost", { listedAfter: Schema.optional(Schema.Finite) }),
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
/** How a release answers. */
|
|
63
|
+
export const Release = Schema.Union([
|
|
64
|
+
/** The session ends at once. */
|
|
65
|
+
Schema.TaggedStruct("Ends", {}),
|
|
66
|
+
/** Accepted, but the session runs on for `millis`, or without them until its timeout. */
|
|
67
|
+
Schema.TaggedStruct("Pending", { millis: Schema.optional(Schema.Finite) }),
|
|
68
|
+
/** Refused with `status`; the session runs on. */
|
|
69
|
+
Schema.TaggedStruct("Refused", { status: Refusal }),
|
|
70
|
+
/** The session ends, but no answer arrives. */
|
|
71
|
+
Schema.TaggedStruct("Lost", {}),
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
/** How a session read answers. */
|
|
75
|
+
export const Read = Schema.Union([
|
|
76
|
+
Schema.TaggedStruct("Answer", {}),
|
|
77
|
+
Schema.TaggedStruct("Refused", { status: Refusal }),
|
|
78
|
+
Schema.TaggedStruct("Lost", {}),
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
export const Script = Schema.Struct({
|
|
82
|
+
/** How creates answer, in turn; once these run out, each is accepted. */
|
|
83
|
+
creates: Schema.optional(Schema.Array(Create)),
|
|
84
|
+
/** How releases answer, in turn; once these run out, each ends its session. */
|
|
85
|
+
releases: Schema.optional(Schema.Array(Release)),
|
|
86
|
+
/** How session reads answer, in turn; once these run out, each answers. */
|
|
87
|
+
reads: Schema.optional(Schema.Array(Read)),
|
|
88
|
+
/** The DevTools address each session hands out. Without it, sessions have none. */
|
|
89
|
+
connectUrl: Schema.optional(Schema.String),
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
export type Script = typeof Script.Type;
|
|
93
|
+
|
|
94
|
+
/** A session as the fake keeps it, with how many releases it was asked. */
|
|
95
|
+
export interface Kept {
|
|
96
|
+
readonly id: string;
|
|
97
|
+
readonly status: string;
|
|
98
|
+
/** The create options as sent, without provider defaults. Only the test handle exposes them. */
|
|
99
|
+
readonly options: SessionOptions;
|
|
100
|
+
readonly userMetadata: Readonly<Record<string, unknown>> | undefined;
|
|
101
|
+
readonly releases: number;
|
|
102
|
+
/** Whether it was created to outlive its connections, until released or timed out. */
|
|
103
|
+
readonly keepAlive: boolean;
|
|
104
|
+
/** The stored context it loaded, and whether it saves to it as it ends. */
|
|
105
|
+
readonly context: { readonly id: string; readonly persist: boolean } | undefined;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface Handle {
|
|
109
|
+
/** Every request, oldest first, as `METHOD /path?query`. */
|
|
110
|
+
readonly requests: Effect.Effect<ReadonlyArray<string>>;
|
|
111
|
+
/** Each session as Browserbase would describe it now, oldest first. */
|
|
112
|
+
readonly sessions: Effect.Effect<ReadonlyArray<Kept>>;
|
|
113
|
+
/** End a session as Browserbase does on its own, as when its browser fails. */
|
|
114
|
+
readonly end: (id: string) => Effect.Effect<void>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** The fake's handle, beside the `BrowserbaseClient` that `layer` runs on it. */
|
|
118
|
+
export class TestBrowserbase extends Context.Service<TestBrowserbase, Handle>()(
|
|
119
|
+
"effect-browserbase/testing/TestBrowserbase",
|
|
120
|
+
) {}
|
|
121
|
+
|
|
122
|
+
/** The API key the fake takes; any other is unauthorized. */
|
|
123
|
+
export const apiKey = "test-browserbase-key";
|
|
124
|
+
|
|
125
|
+
const CreateBody = Schema.fromJsonString(
|
|
126
|
+
Schema.Struct({
|
|
127
|
+
projectId: Schema.optional(Schema.String),
|
|
128
|
+
extensionId: Schema.optional(Schema.String),
|
|
129
|
+
timeout: Schema.optional(Schema.Finite),
|
|
130
|
+
keepAlive: Schema.optional(Schema.Boolean),
|
|
131
|
+
region: Schema.optional(
|
|
132
|
+
Schema.Literals(["us-west-2", "us-east-1", "eu-central-1", "ap-southeast-1"]),
|
|
133
|
+
),
|
|
134
|
+
proxies: Schema.optional(
|
|
135
|
+
Schema.Union([
|
|
136
|
+
Schema.Boolean,
|
|
137
|
+
Schema.Array(
|
|
138
|
+
Schema.Union([
|
|
139
|
+
Schema.Struct({
|
|
140
|
+
type: Schema.Literal("browserbase"),
|
|
141
|
+
geolocation: Schema.optional(
|
|
142
|
+
Schema.Struct({
|
|
143
|
+
country: Schema.String,
|
|
144
|
+
state: Schema.optional(Schema.String),
|
|
145
|
+
city: Schema.optional(Schema.String),
|
|
146
|
+
}),
|
|
147
|
+
),
|
|
148
|
+
domainPattern: Schema.optional(Schema.String),
|
|
149
|
+
}),
|
|
150
|
+
Schema.Struct({
|
|
151
|
+
type: Schema.Literal("external"),
|
|
152
|
+
server: Schema.String,
|
|
153
|
+
username: Schema.optional(Schema.String),
|
|
154
|
+
password: Schema.optional(Schema.String),
|
|
155
|
+
domainPattern: Schema.optional(Schema.String),
|
|
156
|
+
}),
|
|
157
|
+
Schema.Struct({
|
|
158
|
+
type: Schema.Literal("none"),
|
|
159
|
+
domainPattern: Schema.optional(Schema.String),
|
|
160
|
+
}),
|
|
161
|
+
]),
|
|
162
|
+
),
|
|
163
|
+
]),
|
|
164
|
+
),
|
|
165
|
+
userMetadata: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),
|
|
166
|
+
browserSettings: Schema.optional(
|
|
167
|
+
Schema.Struct({
|
|
168
|
+
context: Schema.optional(
|
|
169
|
+
Schema.Struct({ id: Schema.String, persist: Schema.optional(Schema.Boolean) }),
|
|
170
|
+
),
|
|
171
|
+
viewport: Schema.optional(Schema.Struct({ width: Schema.Finite, height: Schema.Finite })),
|
|
172
|
+
blockAds: Schema.optional(Schema.Boolean),
|
|
173
|
+
solveCaptchas: Schema.optional(Schema.Boolean),
|
|
174
|
+
recordSession: Schema.optional(Schema.Boolean),
|
|
175
|
+
logSession: Schema.optional(Schema.Boolean),
|
|
176
|
+
verified: Schema.optional(Schema.Boolean),
|
|
177
|
+
os: Schema.optional(Schema.Literals(["windows", "mac", "linux", "mobile", "tablet"])),
|
|
178
|
+
allowedDomains: Schema.optional(Schema.Array(Schema.String)),
|
|
179
|
+
ignoreCertificateErrors: Schema.optional(Schema.Boolean),
|
|
180
|
+
}),
|
|
181
|
+
),
|
|
182
|
+
}),
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
const ReleaseBody = Schema.fromJsonString(
|
|
186
|
+
Schema.Struct({ status: Schema.Literal("REQUEST_RELEASE") }),
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
interface Row {
|
|
190
|
+
readonly id: string;
|
|
191
|
+
readonly options: SessionOptions;
|
|
192
|
+
readonly createdAt: number;
|
|
193
|
+
/** When a list first shows it. */
|
|
194
|
+
readonly listedAt: number;
|
|
195
|
+
readonly expiresAt: number;
|
|
196
|
+
readonly keepAlive: boolean;
|
|
197
|
+
readonly userMetadata: Readonly<Record<string, unknown>> | undefined;
|
|
198
|
+
readonly context: { readonly id: string; readonly persist: boolean } | undefined;
|
|
199
|
+
/** How and when it ends, unless its timeout comes first. */
|
|
200
|
+
ends: { readonly status: string; readonly at: number } | undefined;
|
|
201
|
+
releases: number;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** Everything one fake keeps. */
|
|
205
|
+
interface Fake {
|
|
206
|
+
readonly now: () => number;
|
|
207
|
+
readonly connectUrl: string | undefined;
|
|
208
|
+
readonly pending: {
|
|
209
|
+
readonly creates: Array<typeof Create.Type>;
|
|
210
|
+
readonly releases: Array<typeof Release.Type>;
|
|
211
|
+
readonly reads: Array<typeof Read.Type>;
|
|
212
|
+
};
|
|
213
|
+
readonly requests: Array<string>;
|
|
214
|
+
readonly sessions: Map<string, Row>;
|
|
215
|
+
readonly contexts: Map<string, number>;
|
|
216
|
+
/** How many sessions and contexts it has made, together, for their ids. */
|
|
217
|
+
readonly made: { count: number };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const iso = (millis: number) => DateTime.formatIso(DateTime.makeUnsafe(millis));
|
|
221
|
+
|
|
222
|
+
const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
223
|
+
|
|
224
|
+
/** The next id, a UUID as Browserbase's are, counted so that every run hands out the same. */
|
|
225
|
+
const nextId = (fake: Fake) =>
|
|
226
|
+
`00000000-0000-4000-8000-${(++fake.made.count).toString(16).padStart(12, "0")}`;
|
|
227
|
+
|
|
228
|
+
/** How the session ended by now, or undefined while it runs. */
|
|
229
|
+
const endOf = (fake: Fake, row: Row) => {
|
|
230
|
+
const end =
|
|
231
|
+
row.ends !== undefined && row.ends.at <= row.expiresAt
|
|
232
|
+
? row.ends
|
|
233
|
+
: { status: "TIMED_OUT", at: row.expiresAt };
|
|
234
|
+
|
|
235
|
+
return end.at <= fake.now() ? end : undefined;
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
/** The session as Browserbase answers it; only creates and reads hand out its address. */
|
|
239
|
+
const describe = (fake: Fake, row: Row, connect: boolean) => {
|
|
240
|
+
const end = endOf(fake, row);
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
id: row.id,
|
|
244
|
+
createdAt: iso(row.createdAt),
|
|
245
|
+
updatedAt: iso(end?.at ?? row.createdAt),
|
|
246
|
+
startedAt: iso(row.createdAt),
|
|
247
|
+
expiresAt: iso(row.expiresAt),
|
|
248
|
+
projectId: row.options.projectId ?? "test-project",
|
|
249
|
+
status: end?.status ?? "RUNNING",
|
|
250
|
+
proxyBytes: 0,
|
|
251
|
+
keepAlive: row.keepAlive,
|
|
252
|
+
region: row.options.region ?? "us-west-2",
|
|
253
|
+
...(end === undefined ? {} : { endedAt: iso(end.at) }),
|
|
254
|
+
...(row.context === undefined ? {} : { contextId: row.context.id }),
|
|
255
|
+
...(row.userMetadata === undefined ? {} : { userMetadata: row.userMetadata }),
|
|
256
|
+
...(connect && fake.connectUrl !== undefined ? { connectUrl: fake.connectUrl } : {}),
|
|
257
|
+
...(connect
|
|
258
|
+
? {
|
|
259
|
+
seleniumRemoteUrl: `https://connect.browserbase.test/webdriver/${row.id}`,
|
|
260
|
+
signingKey: `signing-key-${row.id}`,
|
|
261
|
+
}
|
|
262
|
+
: {}),
|
|
263
|
+
};
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
const bodyText = (request: HttpClientRequest.HttpClientRequest) =>
|
|
267
|
+
request.body._tag === "Uint8Array"
|
|
268
|
+
? (request.body.text ?? new TextDecoder().decode(request.body.body))
|
|
269
|
+
: "";
|
|
270
|
+
|
|
271
|
+
/** A metadata query in Browserbase's one form, `user_metadata['a']['b']:'value'`, as a test. */
|
|
272
|
+
const metadataQuery = (query: string) => {
|
|
273
|
+
const parsed = /^user_metadata((?:\['[^']*'\])+):'([^']*)'$/.exec(query);
|
|
274
|
+
|
|
275
|
+
if (parsed === null) return undefined;
|
|
276
|
+
const path = [...(parsed[1] ?? "").matchAll(/\['([^']*)'\]/g)].map((part) => part[1] ?? "");
|
|
277
|
+
|
|
278
|
+
return (metadata: unknown) =>
|
|
279
|
+
path.reduce<unknown>(
|
|
280
|
+
(value, key) => (Predicate.isObject(value) ? Reflect.get(value, key) : undefined),
|
|
281
|
+
metadata,
|
|
282
|
+
) === parsed[2];
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const unsupported = (detail: string) => Effect.die(new Error(`TestBrowserbase ${detail}`));
|
|
286
|
+
|
|
287
|
+
/** Answer one request as Browserbase would, after the script's say. */
|
|
288
|
+
const serve = (fake: Fake, request: HttpClientRequest.HttpClientRequest, url: URL) => {
|
|
289
|
+
const answer = (status: number, body?: unknown, headers: Record<string, string> = {}) =>
|
|
290
|
+
Effect.succeed(
|
|
291
|
+
HttpClientResponse.fromWeb(
|
|
292
|
+
request,
|
|
293
|
+
new Response(body === undefined ? null : JSON.stringify(body), {
|
|
294
|
+
status,
|
|
295
|
+
headers: { "content-type": "application/json", ...headers },
|
|
296
|
+
}),
|
|
297
|
+
),
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
const lost = Effect.fail(
|
|
301
|
+
new HttpClientError.HttpClientError({
|
|
302
|
+
reason: new HttpClientError.TransportError({
|
|
303
|
+
request,
|
|
304
|
+
description: "TestBrowserbase lost this answer, as its script said",
|
|
305
|
+
}),
|
|
306
|
+
}),
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
const refused = (status: number) => answer(status, { message: "refused, as the script said" });
|
|
310
|
+
const [, version, kind, id, rest] = url.pathname.split("/");
|
|
311
|
+
const row = id === undefined ? undefined : fake.sessions.get(id);
|
|
312
|
+
|
|
313
|
+
fake.requests.push(`${request.method} ${url.pathname}${url.search}`);
|
|
314
|
+
if (request.headers["x-bb-api-key"] !== apiKey)
|
|
315
|
+
return answer(401, { message: "Invalid API key" });
|
|
316
|
+
if (version !== "v1") return unsupported(`serves only /v1, not ${url.pathname}`);
|
|
317
|
+
// Browserbase refuses a session or context id that is not a UUID before it looks for it.
|
|
318
|
+
if ((kind === "sessions" || kind === "contexts") && id !== undefined && !uuid.test(id))
|
|
319
|
+
return answer(400, { message: `Invalid ${kind === "sessions" ? "Session" : "Context"} ID` });
|
|
320
|
+
|
|
321
|
+
switch (
|
|
322
|
+
`${request.method} ${kind}${id === undefined ? "" : " id"}${rest === undefined ? "" : ` ${rest}`}`
|
|
323
|
+
) {
|
|
324
|
+
case "POST sessions": {
|
|
325
|
+
const reply = fake.pending.creates.shift() ?? { _tag: "Accept" };
|
|
326
|
+
|
|
327
|
+
if (reply._tag === "Reject")
|
|
328
|
+
return answer(
|
|
329
|
+
reply.status,
|
|
330
|
+
{ message: "refused, as the script said" },
|
|
331
|
+
reply.retryAfterSeconds === undefined
|
|
332
|
+
? {}
|
|
333
|
+
: { "retry-after": `${reply.retryAfterSeconds}` },
|
|
334
|
+
);
|
|
335
|
+
const body = Option.getOrUndefined(Schema.decodeOption(CreateBody)(bodyText(request)));
|
|
336
|
+
|
|
337
|
+
if (body === undefined) return answer(400, { message: "Invalid session settings" });
|
|
338
|
+
const loaded = body.browserSettings?.context;
|
|
339
|
+
const createdAt = fake.now();
|
|
340
|
+
|
|
341
|
+
const created: Row = {
|
|
342
|
+
id: nextId(fake),
|
|
343
|
+
options: body,
|
|
344
|
+
createdAt,
|
|
345
|
+
listedAt: createdAt + (reply._tag === "Lost" ? (reply.listedAfter ?? 0) : 0),
|
|
346
|
+
expiresAt: createdAt + (body.timeout ?? 300) * 1000,
|
|
347
|
+
keepAlive: body.keepAlive ?? false,
|
|
348
|
+
userMetadata: body.userMetadata,
|
|
349
|
+
context:
|
|
350
|
+
loaded === undefined ? undefined : { id: loaded.id, persist: loaded.persist ?? false },
|
|
351
|
+
ends: undefined,
|
|
352
|
+
releases: 0,
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
fake.sessions.set(created.id, created);
|
|
356
|
+
if (reply._tag === "Lost") return lost;
|
|
357
|
+
|
|
358
|
+
return answer(
|
|
359
|
+
201,
|
|
360
|
+
reply._tag === "Malformed" ? { id: created.id } : describe(fake, created, true),
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
case "GET sessions": {
|
|
364
|
+
const status = url.searchParams.get("status");
|
|
365
|
+
const query = url.searchParams.get("q");
|
|
366
|
+
const matches = query === null ? () => true : metadataQuery(query);
|
|
367
|
+
|
|
368
|
+
if (matches === undefined) return unsupported(`cannot read the query ${query}`);
|
|
369
|
+
|
|
370
|
+
return answer(
|
|
371
|
+
200,
|
|
372
|
+
[...fake.sessions.values()]
|
|
373
|
+
.filter(
|
|
374
|
+
(kept) =>
|
|
375
|
+
kept.listedAt <= fake.now() &&
|
|
376
|
+
(status === null || (endOf(fake, kept)?.status ?? "RUNNING") === status) &&
|
|
377
|
+
matches(kept.userMetadata),
|
|
378
|
+
)
|
|
379
|
+
.map((kept) => describe(fake, kept, false)),
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
case "GET sessions id": {
|
|
383
|
+
const reply = fake.pending.reads.shift() ?? { _tag: "Answer" };
|
|
384
|
+
|
|
385
|
+
if (reply._tag === "Refused") return refused(reply.status);
|
|
386
|
+
if (reply._tag === "Lost") return lost;
|
|
387
|
+
|
|
388
|
+
return row === undefined
|
|
389
|
+
? answer(404, { message: "Session not found" })
|
|
390
|
+
: answer(200, describe(fake, row, true));
|
|
391
|
+
}
|
|
392
|
+
case "GET sessions id debug":
|
|
393
|
+
return row === undefined
|
|
394
|
+
? answer(404, { message: "Session not found" })
|
|
395
|
+
: answer(200, {
|
|
396
|
+
debuggerFullscreenUrl: `https://live.browserbase.test/${row.id}/fullscreen`,
|
|
397
|
+
debuggerUrl: `https://live.browserbase.test/${row.id}`,
|
|
398
|
+
pages: [],
|
|
399
|
+
});
|
|
400
|
+
case "POST sessions id": {
|
|
401
|
+
if (row === undefined) return answer(404, { message: "Session not found" });
|
|
402
|
+
if (Option.isNone(Schema.decodeOption(ReleaseBody)(bodyText(request))))
|
|
403
|
+
return answer(400, { message: "status must be REQUEST_RELEASE" });
|
|
404
|
+
row.releases += 1;
|
|
405
|
+
const reply = fake.pending.releases.shift() ?? { _tag: "Ends" };
|
|
406
|
+
|
|
407
|
+
if (reply._tag === "Refused") return refused(reply.status);
|
|
408
|
+
// Releasing a session that has ended changes nothing, and succeeds.
|
|
409
|
+
if (
|
|
410
|
+
endOf(fake, row) === undefined &&
|
|
411
|
+
(reply._tag !== "Pending" || reply.millis !== undefined)
|
|
412
|
+
)
|
|
413
|
+
row.ends = {
|
|
414
|
+
status: "COMPLETED",
|
|
415
|
+
at: fake.now() + (reply._tag === "Pending" ? (reply.millis ?? 0) : 0),
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
return reply._tag === "Lost" ? lost : answer(200, describe(fake, row, false));
|
|
419
|
+
}
|
|
420
|
+
case "POST contexts": {
|
|
421
|
+
const created = nextId(fake);
|
|
422
|
+
|
|
423
|
+
fake.contexts.set(created, fake.now());
|
|
424
|
+
|
|
425
|
+
return answer(201, {
|
|
426
|
+
id: created,
|
|
427
|
+
publicKey: "test-public-key",
|
|
428
|
+
cipherAlgorithm: "AES-256-CBC",
|
|
429
|
+
initializationVectorSize: 16,
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
case "GET contexts id": {
|
|
433
|
+
const createdAt = id === undefined ? undefined : fake.contexts.get(id);
|
|
434
|
+
|
|
435
|
+
return createdAt === undefined
|
|
436
|
+
? answer(404, { message: "Context not found" })
|
|
437
|
+
: answer(200, {
|
|
438
|
+
id,
|
|
439
|
+
createdAt: iso(createdAt),
|
|
440
|
+
updatedAt: iso(createdAt),
|
|
441
|
+
projectId: "test-project",
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
case "DELETE contexts id":
|
|
445
|
+
return id !== undefined && fake.contexts.delete(id)
|
|
446
|
+
? answer(204)
|
|
447
|
+
: answer(404, { message: "Context not found" });
|
|
448
|
+
default:
|
|
449
|
+
return unsupported(`does not implement ${request.method} ${url.pathname}`);
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
/** The fake as an `HttpClient`, with its handle. */
|
|
454
|
+
export const make = Effect.fnUntraced(function* (script: Script = {}) {
|
|
455
|
+
const clock = yield* Clock.Clock;
|
|
456
|
+
const decoded = yield* Effect.orDie(Schema.decodeEffect(Script)(script));
|
|
457
|
+
|
|
458
|
+
const fake: Fake = {
|
|
459
|
+
now: () => clock.currentTimeMillisUnsafe(),
|
|
460
|
+
connectUrl: decoded.connectUrl,
|
|
461
|
+
pending: {
|
|
462
|
+
creates: [...(decoded.creates ?? [])],
|
|
463
|
+
releases: [...(decoded.releases ?? [])],
|
|
464
|
+
reads: [...(decoded.reads ?? [])],
|
|
465
|
+
},
|
|
466
|
+
requests: [],
|
|
467
|
+
sessions: new Map(),
|
|
468
|
+
contexts: new Map(),
|
|
469
|
+
made: { count: 0 },
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
const handle: Handle = {
|
|
473
|
+
requests: Effect.sync(() => [...fake.requests]),
|
|
474
|
+
sessions: Effect.sync(() =>
|
|
475
|
+
[...fake.sessions.values()].map((row) => ({
|
|
476
|
+
id: row.id,
|
|
477
|
+
options: row.options,
|
|
478
|
+
status: endOf(fake, row)?.status ?? "RUNNING",
|
|
479
|
+
userMetadata: row.userMetadata,
|
|
480
|
+
releases: row.releases,
|
|
481
|
+
keepAlive: row.keepAlive,
|
|
482
|
+
context: row.context,
|
|
483
|
+
})),
|
|
484
|
+
),
|
|
485
|
+
end: (id) =>
|
|
486
|
+
Effect.sync(() => {
|
|
487
|
+
const row = fake.sessions.get(id);
|
|
488
|
+
|
|
489
|
+
if (row !== undefined && endOf(fake, row) === undefined)
|
|
490
|
+
row.ends = { status: "ERROR", at: fake.now() };
|
|
491
|
+
}),
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
return { http: HttpClient.make((request, url) => serve(fake, request, url)), handle };
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
/** The real `BrowserbaseClient` over the fake, and the fake's handle. */
|
|
498
|
+
export const layer = (script: Script = {}): Layer.Layer<BrowserbaseClient | TestBrowserbase> =>
|
|
499
|
+
Layer.unwrap(
|
|
500
|
+
Effect.map(make(script), ({ http, handle }) =>
|
|
501
|
+
Layer.merge(
|
|
502
|
+
clientLayer({
|
|
503
|
+
apiKey: Redacted.make(apiKey),
|
|
504
|
+
baseUrl: "https://api.browserbase.test",
|
|
505
|
+
}).pipe(Layer.provide(Layer.succeed(HttpClient.HttpClient, http))),
|
|
506
|
+
Layer.succeed(TestBrowserbase, handle),
|
|
507
|
+
),
|
|
508
|
+
),
|
|
509
|
+
);
|
package/dist/Account.d.mts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { ClientError } from "./Errors.mjs";
|
|
2
|
-
import { r as ClientOptions, t as BrowserbaseClient } from "./Client-B_f6bBLT.mjs";
|
|
3
|
-
import { p as BrowserbaseAgents } from "./Agents-CPaTOH_g.mjs";
|
|
4
|
-
import { t as BrowserbaseCertificates } from "./Certificates-D4NQmyeA.mjs";
|
|
5
|
-
import { t as BrowserbaseContexts } from "./Contexts-DqdL7cyX.mjs";
|
|
6
|
-
import { t as BrowserbaseSessions } from "./Sessions-oJEUmZth.mjs";
|
|
7
|
-
import { t as BrowserbaseDownloads } from "./Downloads-CX52GOFJ.mjs";
|
|
8
|
-
import { t as BrowserbaseExtensions } from "./Extensions-DBXuVM1f.mjs";
|
|
9
|
-
import { t as BrowserbaseFunctions } from "./Functions-CsKMMUuZ.mjs";
|
|
10
|
-
import { t as BrowserbasePageFetch } from "./PageFetch-CjAM_0DS.mjs";
|
|
11
|
-
import { t as BrowserbaseProjects } from "./Projects-tm5bTDH0.mjs";
|
|
12
|
-
import { t as BrowserbaseRecordings } from "./Recordings-B9k5aODB.mjs";
|
|
13
|
-
import { t as BrowserbaseReplays } from "./Replays-mV93WGtx.mjs";
|
|
14
|
-
import { t as BrowserbaseSearch } from "./Search-B64e7g-h.mjs";
|
|
15
|
-
import { t as BrowserbaseUploads } from "./Uploads-C2_bACgv.mjs";
|
|
16
|
-
import { t as BrowserbaseWebhooks } from "./Webhooks-BoeRAxzG.mjs";
|
|
17
|
-
import { Config, Layer } from "effect";
|
|
18
|
-
//#region src/Account.d.ts
|
|
19
|
-
/** Every resource service this package owns, on one account's authority. */
|
|
20
|
-
export type Services = BrowserbaseAgents | BrowserbaseCertificates | BrowserbaseClient | BrowserbaseContexts | BrowserbaseDownloads | BrowserbaseExtensions | BrowserbaseFunctions | BrowserbasePageFetch | BrowserbaseProjects | BrowserbaseRecordings | BrowserbaseReplays | BrowserbaseSearch | BrowserbaseSessions | BrowserbaseUploads | BrowserbaseWebhooks;
|
|
21
|
-
/**
|
|
22
|
-
* One account for every resource operation, so credentials are composed once rather than
|
|
23
|
-
* per service. Building it performs no I/O, allocates nothing and loads no native peer;
|
|
24
|
-
* `BrowserbaseBrowser.layer` is deliberately separate, because a browser fixes budgets and
|
|
25
|
-
* a connection lifetime that an account does not.
|
|
26
|
-
*/
|
|
27
|
-
export declare const layer: (options: ClientOptions) => Layer.Layer<Services, ClientError>;
|
|
28
|
-
/** The same bundle, taking account authority from the application's `ConfigProvider`. */
|
|
29
|
-
export declare const layerConfig: (options?: Omit<ClientOptions, "projectId" | "apiKey">) => Layer.Layer<Services, ClientError | Config.ConfigError>;
|
|
30
|
-
//#endregion
|
|
31
|
-
export {};
|
|
32
|
-
//# sourceMappingURL=Account.d.mts.map
|
package/dist/Account.mjs
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { t as BrowserbaseClient } from "./Client-BEC4Q8ZS.mjs";
|
|
2
|
-
import { BrowserbaseAgents } from "./Agents.mjs";
|
|
3
|
-
import { BrowserbaseCertificates } from "./Certificates.mjs";
|
|
4
|
-
import { BrowserbaseContexts } from "./Contexts.mjs";
|
|
5
|
-
import { t as BrowserbaseSessions } from "./Sessions-D2H5m6rF.mjs";
|
|
6
|
-
import { BrowserbaseDownloads } from "./Downloads.mjs";
|
|
7
|
-
import { t as BrowserbaseExtensions } from "./Extensions-BTUn9zhK.mjs";
|
|
8
|
-
import { BrowserbaseFunctions } from "./Functions.mjs";
|
|
9
|
-
import { BrowserbasePageFetch } from "./PageFetch.mjs";
|
|
10
|
-
import { BrowserbaseProjects } from "./Projects.mjs";
|
|
11
|
-
import { BrowserbaseRecordings } from "./Recordings.mjs";
|
|
12
|
-
import { BrowserbaseReplays } from "./Replays.mjs";
|
|
13
|
-
import { BrowserbaseSearch } from "./Search.mjs";
|
|
14
|
-
import { BrowserbaseUploads } from "./Uploads.mjs";
|
|
15
|
-
import { BrowserbaseWebhooks } from "./Webhooks.mjs";
|
|
16
|
-
import { Layer } from "effect";
|
|
17
|
-
//#region src/Account.ts
|
|
18
|
-
/**
|
|
19
|
-
* The services that read one Client. Sessions is provided first and kept in the output,
|
|
20
|
-
* because the artifact services read it and a caller composing this Layer should not have
|
|
21
|
-
* to know which ones do.
|
|
22
|
-
*/
|
|
23
|
-
const services = Layer.mergeAll(BrowserbaseAgents.layer, BrowserbaseCertificates.layer, BrowserbaseContexts.layer, BrowserbaseDownloads.layer, BrowserbaseExtensions.layer, BrowserbaseFunctions.layer, BrowserbasePageFetch.layer, BrowserbaseProjects.layer, BrowserbaseRecordings.layer, BrowserbaseReplays.layer, BrowserbaseSearch.layer, BrowserbaseUploads.layer, BrowserbaseWebhooks.layer).pipe(Layer.provideMerge(BrowserbaseSessions.layer));
|
|
24
|
-
/**
|
|
25
|
-
* One account for every resource operation, so credentials are composed once rather than
|
|
26
|
-
* per service. Building it performs no I/O, allocates nothing and loads no native peer;
|
|
27
|
-
* `BrowserbaseBrowser.layer` is deliberately separate, because a browser fixes budgets and
|
|
28
|
-
* a connection lifetime that an account does not.
|
|
29
|
-
*/
|
|
30
|
-
const layer = (options) => services.pipe(Layer.provideMerge(BrowserbaseClient.layer(options)));
|
|
31
|
-
/** The same bundle, taking account authority from the application's `ConfigProvider`. */
|
|
32
|
-
const layerConfig = (options = {}) => services.pipe(Layer.provideMerge(BrowserbaseClient.layerConfig(options)));
|
|
33
|
-
//#endregion
|
|
34
|
-
export { layer, layerConfig };
|
|
35
|
-
|
|
36
|
-
//# sourceMappingURL=Account.mjs.map
|
package/dist/Account.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Account.mjs","names":[],"sources":["../src/Account.ts"],"sourcesContent":["import { type Config, Layer } from \"effect\";\n\nimport { BrowserbaseAgents } from \"./Agents.ts\";\nimport { BrowserbaseCertificates } from \"./Certificates.ts\";\nimport { BrowserbaseClient, type ClientOptions } from \"./Client.ts\";\nimport { BrowserbaseContexts } from \"./Contexts.ts\";\nimport { BrowserbaseDownloads } from \"./Downloads.ts\";\nimport type { ClientError } from \"./Errors.ts\";\nimport { BrowserbaseExtensions } from \"./Extensions.ts\";\nimport { BrowserbaseFunctions } from \"./Functions.ts\";\nimport { BrowserbasePageFetch } from \"./PageFetch.ts\";\nimport { BrowserbaseProjects } from \"./Projects.ts\";\nimport { BrowserbaseRecordings } from \"./Recordings.ts\";\nimport { BrowserbaseReplays } from \"./Replays.ts\";\nimport { BrowserbaseSearch } from \"./Search.ts\";\nimport { BrowserbaseSessions } from \"./Sessions.ts\";\nimport { BrowserbaseUploads } from \"./Uploads.ts\";\nimport { BrowserbaseWebhooks } from \"./Webhooks.ts\";\n\n/** Every resource service this package owns, on one account's authority. */\nexport type Services =\n | BrowserbaseAgents\n | BrowserbaseCertificates\n | BrowserbaseClient\n | BrowserbaseContexts\n | BrowserbaseDownloads\n | BrowserbaseExtensions\n | BrowserbaseFunctions\n | BrowserbasePageFetch\n | BrowserbaseProjects\n | BrowserbaseRecordings\n | BrowserbaseReplays\n | BrowserbaseSearch\n | BrowserbaseSessions\n | BrowserbaseUploads\n | BrowserbaseWebhooks;\n\n/**\n * The services that read one Client. Sessions is provided first and kept in the output,\n * because the artifact services read it and a caller composing this Layer should not have\n * to know which ones do.\n */\nconst services = Layer.mergeAll(\n BrowserbaseAgents.layer,\n BrowserbaseCertificates.layer,\n BrowserbaseContexts.layer,\n BrowserbaseDownloads.layer,\n BrowserbaseExtensions.layer,\n BrowserbaseFunctions.layer,\n BrowserbasePageFetch.layer,\n BrowserbaseProjects.layer,\n BrowserbaseRecordings.layer,\n BrowserbaseReplays.layer,\n BrowserbaseSearch.layer,\n BrowserbaseUploads.layer,\n BrowserbaseWebhooks.layer,\n).pipe(Layer.provideMerge(BrowserbaseSessions.layer));\n\n/**\n * One account for every resource operation, so credentials are composed once rather than\n * per service. Building it performs no I/O, allocates nothing and loads no native peer;\n * `BrowserbaseBrowser.layer` is deliberately separate, because a browser fixes budgets and\n * a connection lifetime that an account does not.\n */\nexport const layer = (options: ClientOptions): Layer.Layer<Services, ClientError> =>\n services.pipe(Layer.provideMerge(BrowserbaseClient.layer(options)));\n\n/** The same bundle, taking account authority from the application's `ConfigProvider`. */\nexport const layerConfig = (\n options: Omit<ClientOptions, \"projectId\" | \"apiKey\"> = {},\n): Layer.Layer<Services, ClientError | Config.ConfigError> =>\n services.pipe(Layer.provideMerge(BrowserbaseClient.layerConfig(options)));\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA0CA,MAAM,WAAW,MAAM,SACrB,kBAAkB,OAClB,wBAAwB,OACxB,oBAAoB,OACpB,qBAAqB,OACrB,sBAAsB,OACtB,qBAAqB,OACrB,qBAAqB,OACrB,oBAAoB,OACpB,sBAAsB,OACtB,mBAAmB,OACnB,kBAAkB,OAClB,mBAAmB,OACnB,oBAAoB,KACtB,CAAC,CAAC,KAAK,MAAM,aAAa,oBAAoB,KAAK,CAAC;;;;;;;AAQpD,MAAa,SAAS,YACpB,SAAS,KAAK,MAAM,aAAa,kBAAkB,MAAM,OAAO,CAAC,CAAC;;AAGpE,MAAa,eACX,UAAuD,CAAC,MAExD,SAAS,KAAK,MAAM,aAAa,kBAAkB,YAAY,OAAO,CAAC,CAAC"}
|