effect-browserbase 0.3.0-beta.13 → 0.3.0-beta.15

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 CHANGED
@@ -16,7 +16,8 @@ npm install effect-browserbase@beta effect-browser@beta effect playwright-core
16
16
  - `ContextLease`: who may write a stored context. `ContextLease.layer` lets one writer at a time
17
17
  hold each context in this process; an application provides its own to exclude writers across
18
18
  processes. A persisting open that will not write to a context whose sessions may still save to
19
- it fails with `ContextHeld`.
19
+ it fails with `ContextHeld`. A custom lease can refuse a writer permanently with `ContextRefused`;
20
+ `open`, `verifyContext` and `reconcile` preserve that error, and supervision stops retrying it.
20
21
  - `BrowserbaseClient`: sessions, Live View, stored contexts, extensions, Search and Fetch.
21
22
  `layerConfig()` reads `BROWSERBASE_API_KEY` and, optionally, `BROWSERBASE_BASE_URL`.
22
23
  - `BrowserbaseError`: one error with a reason: `Unauthorized`, `NotFound`, `RateLimited`, `Status`,
@@ -53,8 +54,8 @@ Each create `open` sends carries a nonce of its own in the session's user metada
53
54
  A create whose answer was lost, or that Browserbase answered 5xx or 408, may still have made a
54
55
  session that nobody can see, and that bills until its timeout: `open` looks for it by its nonce,
55
56
  again and again for up to 30 seconds, since Browserbase can list a new session late, ends it, and
56
- then fails with the create's error. A `supervise` that tries again after such failures leaves no
57
- session behind each try.
57
+ then fails with the create's error. `supervise` reports that cleanup's outcome to the next
58
+ attempt's admission, including when a session it found could not be confirmed ended.
58
59
 
59
60
  `open` and `attach` record the session's id and region on their spans, so a trace finds its
60
61
  session in Browserbase's dashboard (`https://browserbase.com/sessions/<id>`).
@@ -87,7 +88,8 @@ The [generic supervisor contract](../browser/README.md#supervising-browser-gener
87
88
  `use`, transferable `retain` scopes, cancellation and stale-work refusal.
88
89
 
89
90
  Outgoing holds drain for `handover`, 30 seconds by default. A lost session revokes immediately and
90
- is replaced on `reopen`; `rotateBefore` and `rotate` keep their normal schedule while older
91
+ is replaced on `reopen`; a consumer can declare the same loss with `lease.lose(detail)`.
92
+ `rotateBefore` and `rotate` keep their normal schedule while older
91
93
  nonexclusive generations drain. This can overlap more than two hosted sessions. The consumer
92
94
  owns its overlap and billing policy. `states` reports each generation's release outcome;
93
95
  `Unconfirmed` means the old session might still run even after local ownership ends.
@@ -96,8 +98,21 @@ Sessions that persist to a stored context are exclusive: rotation first drains t
96
98
  generation, releases its session and lets its save settle. If release is unconfirmed, the next
97
99
  writer reconciles the context and fails `ContextHeld` while the old writer cannot be confirmed
98
100
  ended. It does not silently create another writer. An open Browserbase refused, as for a bad key
99
- or an invalid request, is `Down` at once; everything else, a held context included, is tried again
100
- on the schedule.
101
+ or an invalid request, and a permanent `ContextRefused`, are `Down` at once. Temporary `ContextHeld`
102
+ failures are tried again on the schedule. `definite(error)` can also stop retries for application
103
+ failures, including those from `build` or `admit`.
104
+
105
+ `admit({ number, after })` runs before each attempt, including the first, before acquiring a
106
+ context lease or making a provider request. `after`, when present, covers every session the
107
+ supervisor started that no longer serves: prior generations still releasing and failed attempts,
108
+ including a failed connection or `build`. It waits for all their releases and is `Unconfirmed`
109
+ if any was; the first unconfirmed outcome remains visible on later attempts and identifies its
110
+ session when known.
111
+ Await it to enforce an account policy such as refusing a reopen after an `Unconfirmed` release;
112
+ ignoring it preserves immediate reopening. The serving predecessor of a healthy nonexclusive
113
+ rotation is excluded, so the same policy keeps ephemeral rotations opening the replacement
114
+ before releasing the outgoing session. Admission shares the opening fiber's retry and
115
+ cancellation rules.
101
116
 
102
117
  ```ts
103
118
  const program = Effect.gen(function* () {
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
2
  import { BrowserbaseError, Decode, InvalidRequest, isTransient } from "./BrowserbaseError.mjs";
3
3
  import { BrowserbaseClient } from "./BrowserbaseClient.mjs";
4
- import { ContextHeld, ContextLease } from "./ContextLease.mjs";
4
+ import { ContextHeld, ContextLease, ContextRefused } from "./ContextLease.mjs";
5
5
  import { DateTime, Duration, Effect, Exit, Layer, Option, Random, Redacted, Schedule, Schema, Scope, Semaphore } from "effect";
6
6
  import * as Browser from "effect-browser/Browser";
7
7
  import { BrowserError, Closed, Failed } from "effect-browser/BrowserError";
@@ -220,7 +220,7 @@ const confirm = (client, id, settle) => Effect.gen(function* () {
220
220
  }), Effect.exit, Effect.andThen(read), Effect.as(true), Effect.timeoutOrElse({
221
221
  duration: releaseDeadline,
222
222
  orElse: () => Effect.succeed(false)
223
- }), Effect.orElseSucceed(() => false)))) return new Supervisor.Unconfirmed({ detail: `${last} ${Duration.format(releaseDeadline)} after its release` });
223
+ }), Effect.orElseSucceed(() => false)))) return new Supervisor.Unconfirmed({ detail: `Session ${id}: ${last} ${Duration.format(releaseDeadline)} after its release` });
224
224
  if (settle !== void 0) yield* Effect.sleep(settle);
225
225
  return new Supervisor.Settled();
226
226
  }).pipe(Effect.tap((released) => Effect.annotateCurrentSpan({ released: released._tag })), Effect.withSpan("Browserbase.release", { attributes: {
@@ -386,6 +386,8 @@ const adoptable = Effect.fnUntraced(function* (client, name, persisting) {
386
386
  const start = Effect.fnUntraced(function* (options, keeping) {
387
387
  const client = yield* BrowserbaseClient;
388
388
  const lease = yield* ContextLease;
389
+ const reporting = yield* Effect.serviceOption(Supervisor.Releasing);
390
+ const report = (outcome) => Option.isSome(reporting) ? reporting.value.released(outcome) : Effect.void;
389
391
  const context = options.session?.browserSettings?.context;
390
392
  const persisting = context?.persist === true ? context.id : void 0;
391
393
  const local = yield* Scope.fork(yield* Effect.scope);
@@ -417,7 +419,7 @@ const start = Effect.fnUntraced(function* (options, keeping) {
417
419
  const session = adopted === void 0 ? yield* client.createSession(withLabels(options.session, own, persisting, keeping?.name)) : yield* client.getSession(adopted.id);
418
420
  yield* writing?.writing ?? Effect.void;
419
421
  return yield* ending(session);
420
- }), ({ release, leave }, exit) => keeping !== void 0 && Exit.isSuccess(exit) ? leave : Effect.asVoid(release)).pipe(Effect.tapError((error) => adopted === void 0 && mayHaveCreated(error) ? endOrphan(client, own, writing && settle).pipe(Effect.flatMap((outcome) => writing?.lost(outcome) ?? Effect.void)) : Effect.void));
422
+ }), ({ release, leave }, exit) => keeping !== void 0 && Exit.isSuccess(exit) ? leave : release.pipe(Effect.flatMap((outcome) => Exit.isFailure(exit) ? report(outcome) : Effect.void))).pipe(Effect.tapError((error) => adopted === void 0 && mayHaveCreated(error) ? endOrphan(client, own, writing && settle).pipe(Effect.tap(report), Effect.flatMap((outcome) => writing?.lost(outcome) ?? Effect.void)) : Effect.void));
421
423
  yield* Effect.annotateCurrentSpan({
422
424
  session: session.id,
423
425
  region: session.region,
@@ -506,10 +508,10 @@ const verifyContext = Effect.fn("Browserbase.verifyContext")(function* (contextI
506
508
  return yield* check(browser);
507
509
  }, Effect.scoped);
508
510
  /**
509
- * Browserbase refused the request: no new try mends a refused key, request or id. A context held
510
- * is not among them, since each try ends its sessions again.
511
+ * No new try mends a refused key, request, id or context policy. A context held temporarily is
512
+ * not among them, since each try can take its lease and end its sessions again.
511
513
  */
512
- const refused = (error) => Schema.is(BrowserbaseError)(error) && !isTransient(error) && error.reason._tag !== "Decode";
514
+ const refused = (error) => Schema.is(ContextRefused)(error) || Schema.is(BrowserbaseError)(error) && !isTransient(error) && error.reason._tag !== "Decode";
513
515
  function supervise(options = {}) {
514
516
  return Effect.suspend(() => {
515
517
  const { keep } = options;
@@ -530,7 +532,8 @@ function supervise(options = {}) {
530
532
  exclusive: options.session?.browserSettings?.context?.persist === true,
531
533
  keep: keep !== void 0,
532
534
  reopen: options.reopen,
533
- definite: refused,
535
+ admit: options.admit,
536
+ definite: (error) => refused(error) || options.definite?.(error) === true,
534
537
  rotateBefore: options.rotateBefore,
535
538
  waitTimeout: options.waitTimeout,
536
539
  handover: options.handover
@@ -541,4 +544,4 @@ const layer = (options = {}) => Layer.effect(Browser.Browser, Effect.map(open(op
541
544
  //#endregion
542
545
  export { reconcile as a, open as i, attach as n, supervise as o, layer as r, verifyContext as s, Browserbase_exports as t };
543
546
 
544
- //# sourceMappingURL=Browserbase-CaPKwEY9.mjs.map
547
+ //# sourceMappingURL=Browserbase-COF_pYa8.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Browserbase-COF_pYa8.mjs","names":["CaptureConnection.make"],"sources":["../src/internal/captureConnection.ts","../src/Browserbase.ts"],"sourcesContent":["/**\n * The capture connection: a second DevTools connection to a session, for its pages' screencasts\n * alone. A frame and its acknowledgement then never wait behind a large message on the\n * connection Playwright drives the pages over, such as an upload or a read's answer: Browserbase\n * refuses compression, and on air those waits stopped the picture for as long as the message took\n * to cross.\n *\n * Raw CDP over the global WebSocket, with no Playwright. A page's session on it sends only the\n * capture's commands, and receives that page's events. The connection opens as the first capture\n * starts and stays until the scope closes, which closes it and waits, bounded, for it to close;\n * one that fails ends every page's session on it, and the next capture opens another.\n */\nimport { Duration, Effect, Option, Redacted, Schema, Semaphore } from \"effect\";\nimport type { CaptureSource } from \"effect-browser/Browser\";\nimport { BrowserError, Failed } from \"effect-browser/BrowserError\";\n\nconst Message = Schema.fromJsonString(\n Schema.Struct({\n id: Schema.optionalKey(Schema.Int),\n sessionId: Schema.optionalKey(Schema.String),\n method: Schema.optionalKey(Schema.String),\n params: Schema.optionalKey(Schema.Unknown),\n result: Schema.optionalKey(Schema.Unknown),\n error: Schema.optionalKey(Schema.Struct({ message: Schema.String })),\n }),\n);\n\nconst Session = Schema.Struct({ sessionId: Schema.String });\n\ntype Listener = Parameters<CaptureSource[\"attach\"]>[1];\n\ninterface Open {\n readonly socket: WebSocket;\n /** Replies awaited, by command id. */\n readonly replies: Map<\n number,\n { readonly resolve: (result: unknown) => void; readonly reject: (error: BrowserError) => void }\n >;\n /** Each attached page's listener, by its session id. */\n readonly sessions: Map<string, Listener>;\n}\n\ntype State =\n | { readonly _tag: \"Idle\" }\n | { readonly _tag: \"Open\"; readonly open: Open }\n | { readonly _tag: \"Closed\" };\n\nconst failure = (detail: string) =>\n new BrowserError({ operation: \"screencast\", reason: new Failed({ detail }), dispatched: false });\n\nconst closing = Duration.seconds(2);\n\n/** The capture connection to the DevTools address `url`, for the scope. */\nexport const make = Effect.fnUntraced(function* (url: Redacted.Redacted<string>) {\n let state: State = { _tag: \"Idle\" };\n let ids = 0;\n const opening = yield* Semaphore.make(1);\n\n // A failure ends every page's session on the connection; the next capture opens another.\n const lose = (open: Open, error: BrowserError) => {\n if (state._tag !== \"Open\" || state.open !== open) return;\n state = { _tag: \"Idle\" };\n for (const reply of open.replies.values()) reply.reject(error);\n for (const listener of open.sessions.values()) listener.lost(error);\n open.replies.clear();\n open.sessions.clear();\n };\n\n const receive = (open: Open, data: unknown) => {\n const decoded = typeof data === \"string\" ? Schema.decodeOption(Message)(data) : Option.none();\n\n if (Option.isNone(decoded))\n return lose(open, failure(\"the capture connection sent a message it could not read\"));\n const { id, sessionId, method, params, result, error } = decoded.value;\n\n if (id !== undefined) {\n const reply = open.replies.get(id);\n\n open.replies.delete(id);\n if (error === undefined) reply?.resolve(result);\n else reply?.reject(failure(error.message));\n } else if (method === undefined) return;\n else if (sessionId !== undefined) open.sessions.get(sessionId)?.event(method, params);\n // The connection's own session announces that a page's session ended.\n else if (method === \"Target.detachedFromTarget\") {\n const detached = Schema.decodeUnknownOption(Session)(params);\n const ended = Option.isSome(detached) ? detached.value.sessionId : \"\";\n const listener = open.sessions.get(ended);\n\n open.sessions.delete(ended);\n listener?.event(method, params);\n }\n };\n\n const send = (\n open: Open,\n method: string,\n params: Record<string, unknown> | undefined,\n sessionId?: string,\n ) => {\n if (state._tag !== \"Open\" || state.open !== open)\n return Promise.reject(failure(\"the capture connection was lost\"));\n const id = ++ids;\n const { promise, resolve, reject } = Promise.withResolvers<unknown>();\n\n open.replies.set(id, { resolve, reject });\n try {\n open.socket.send(JSON.stringify({ id, method, params, sessionId }));\n } catch {\n open.replies.delete(id);\n reject(failure(\"the capture connection could not send\"));\n }\n\n return promise;\n };\n\n const connect = Effect.callback<Open, BrowserError>((resume) => {\n const socket = new WebSocket(Redacted.value(url));\n const open: Open = { socket, replies: new Map(), sessions: new Map() };\n\n const unopened = () => resume(Effect.fail(failure(\"the capture connection did not open\")));\n\n socket.addEventListener(\"close\", unopened, { once: true });\n socket.addEventListener(\n \"open\",\n () => {\n socket.removeEventListener(\"close\", unopened);\n // A scope that closed meanwhile keeps no connection.\n if (state._tag === \"Closed\") {\n socket.close(1000);\n\n return resume(Effect.fail(failure(\"the capture connection is closed\")));\n }\n state = { _tag: \"Open\", open };\n socket.addEventListener(\"close\", () =>\n lose(open, failure(\"the capture connection was lost\")),\n );\n resume(Effect.succeed(open));\n },\n { once: true },\n );\n socket.addEventListener(\"message\", ({ data }: MessageEvent<unknown>) => receive(open, data));\n\n return Effect.sync(() => socket.close(1000));\n });\n\n const current = opening.withPermits(1)(\n Effect.suspend(() =>\n state._tag === \"Open\"\n ? Effect.succeed(state.open)\n : state._tag === \"Closed\"\n ? Effect.fail(failure(\"the capture connection is closed\"))\n : connect,\n ),\n );\n\n const replied = (reply: () => Promise<unknown>) =>\n Effect.tryPromise({\n try: reply,\n catch: (cause) =>\n Schema.is(BrowserError)(cause) ? cause : failure(\"the capture connection failed\"),\n });\n\n const attach: CaptureSource[\"attach\"] = (target, listener) =>\n Effect.gen(function* () {\n const open = yield* current;\n\n const { sessionId } = yield* replied(() =>\n send(open, \"Target.attachToTarget\", { targetId: target, flatten: true }),\n ).pipe(\n Effect.flatMap((result) =>\n Schema.decodeUnknownEffect(Session)(result).pipe(\n Effect.mapError(() => failure(\"the capture connection's attach had no session\")),\n ),\n ),\n );\n\n open.sessions.set(sessionId, listener);\n // Detached as the page's scope closes; a connection that closes detaches every session.\n yield* Effect.addFinalizer(() =>\n Effect.sync(() => {\n if (open.sessions.delete(sessionId))\n void send(open, \"Target.detachFromTarget\", { sessionId }, undefined).catch(\n () => undefined,\n );\n }),\n );\n\n return (method, params) => send(open, method, params, sessionId);\n });\n\n // Closing the scope closes the connection and waits, bounded, until it has closed.\n yield* Effect.addFinalizer(() =>\n Effect.suspend(() => {\n const previous = state;\n\n state = { _tag: \"Closed\" };\n if (previous._tag !== \"Open\") return Effect.void;\n const { socket, replies, sessions } = previous.open;\n\n for (const reply of replies.values()) reply.reject(failure(\"the capture connection closed\"));\n replies.clear();\n sessions.clear();\n\n return Effect.callback<void>((resume) => {\n if (socket.readyState === WebSocket.CLOSED) return resume(Effect.void);\n socket.addEventListener(\"close\", () => resume(Effect.void), { once: true });\n socket.close(1000);\n }).pipe(Effect.timeoutOrElse({ duration: closing, orElse: () => Effect.void }));\n }),\n );\n\n return { attach } satisfies CaptureSource;\n});\n","/**\n * A `Browser` running on Browserbase.\n *\n * `open` creates a session and connects to it over CDP. When its scope closes it disconnects,\n * releases the session and confirms that Browserbase reports it ended, so billing stops then\n * rather than at the session's timeout. `release` does the same sooner and says how it went:\n * `Settled`, or `Unconfirmed` when Browserbase still reported the session running, or could not\n * be asked, at the deadline. Each create carries a nonce of its own in its user metadata, so a\n * session made by a create whose answer was lost is found and ended too, rather than billing\n * unseen until its timeout.\n *\n * A session that persists to a stored context saves to it when the session ends, so two at once\n * can lose one's changes. `open` holds the context through the `ContextLease` the application\n * provides, from before it creates such a session until Browserbase reports the session ended and\n * `contextSettle` has passed, since the save lands later and nothing acknowledges it. A writer that\n * leaves a session that saves to the context possibly running, its release `Unconfirmed`, its\n * create's answer lost or its session kept, leaves the context unsettled: the next writer first ends\n * the context's sessions, which `open` labels in their user metadata, and fails with `ContextHeld`\n * while they can't be confirmed ended. `reconcile` ends them without opening, and `verifyContext`\n * reads a context back under the same hold, from a session that saves nothing.\n *\n * `attach` connects to a session that already runs, as from another process: its pages keep their\n * ids, so a page stored before is found again. `supervise` keeps a session open across losses and\n * session ends, as `Supervisor` generations, and with `keep`, past its own scope, for the next\n * `supervise` to adopt.\n *\n * @since 0.3.0\n */\nimport {\n DateTime,\n Duration,\n Effect,\n Exit,\n Layer,\n Option,\n Random,\n Redacted,\n Schedule,\n Schema,\n Scope,\n} from \"effect\";\nimport * as Browser from \"effect-browser/Browser\";\nimport { BrowserError, Closed } from \"effect-browser/BrowserError\";\nimport * as Cdp from \"effect-browser/Cdp\";\nimport * as Supervisor from \"effect-browser/Supervisor\";\n\nimport {\n BrowserbaseClient,\n type Service,\n type Session,\n type SessionOptions,\n} from \"./BrowserbaseClient.ts\";\nimport { BrowserbaseError, Decode, InvalidRequest, isTransient } from \"./BrowserbaseError.ts\";\nimport { ContextHeld, ContextLease, ContextRefused } from \"./ContextLease.ts\";\nimport * as CaptureConnection from \"./internal/captureConnection.ts\";\n\nexport interface Options extends Browser.Options {\n readonly session?: SessionOptions | undefined;\n /** Bound on connecting to the session. Defaults to 30 seconds. */\n readonly connectTimeoutMillis?: number | undefined;\n /**\n * How long a persisting session's context stays held after the session ends, for its save to\n * land. Defaults to 10 seconds, after which hosted checks have read a save back.\n */\n readonly contextSettle?: Duration.Input | undefined;\n /**\n * Run the pages' screencasts on a second connection to the session, which carries nothing else,\n * so that a frame never waits behind a large message, such as an upload or a read's answer, on\n * the connection that drives the page. Defaults to true.\n */\n readonly captureConnection?: boolean | undefined;\n}\n\n/** A browser on a Browserbase session. */\nexport interface Hosted {\n readonly browser: Browser.Service;\n readonly session: Session;\n /**\n * Release the session and confirm it ended, once: `open`'s scope runs it as it closes, while\n * `attach`'s only disconnects. It disconnects `browser` first, which is lost as `released`, so a\n * call in flight or a capture's reader is told so. Asked again, it reports the same outcome.\n */\n readonly release: Effect.Effect<Supervisor.Released>;\n}\n\n/** The user metadata key naming the stored context a persisting session writes to. */\nconst contextLabel = \"persistsContext\";\n\n/** The user metadata key holding each create's own nonce, which finds a session made unseen. */\nconst createLabel = \"createNonce\";\n\n/** The user metadata key naming what a supervisor keeps its sessions under, past its scope. */\nconst keepLabel = \"keptAs\";\n\n/**\n * How long a create whose answer was lost has its session looked for: Browserbase can list a new\n * session late, or still be making it when the client stops waiting.\n */\nconst orphanSearch = Duration.seconds(30);\n\n/** How long a release waits for Browserbase to report the session ended. */\nconst releaseDeadline = Duration.minutes(1);\n\nconst ended = (session: Session) => session.status !== \"PENDING\" && session.status !== \"RUNNING\";\n\n/**\n * End the session and confirm Browserbase reports it ended. The release request and the status\n * reads are each tried again a second apart until the deadline; a session still running then, or\n * one Browserbase could not be asked about, is `Unconfirmed`. Once it has ended, wait `settle`\n * longer, for its context's save to land. It runs to the end once started.\n */\nconst confirm = (client: Service, id: string, settle: Duration.Duration | undefined) =>\n Effect.gen(function* () {\n // What Browserbase last said, for an end it never confirmed.\n let last = \"Browserbase did not answer\";\n\n const heard = (error: BrowserbaseError) => Effect.sync(() => (last = error.message));\n\n const read = client.getSession(id).pipe(\n Effect.tapError(heard),\n Effect.tap((session) => Effect.sync(() => (last = `the session was ${session.status}`))),\n Effect.retry(Schedule.spaced(\"1 second\")),\n Effect.repeat({ until: ended, schedule: Schedule.spaced(\"1 second\") }),\n );\n\n // A release that keeps failing leaves the status reads to tell whether the session ended.\n const confirmed = yield* client.releaseSession(id).pipe(\n Effect.tapError(heard),\n Effect.retry({ while: isTransient, schedule: Schedule.spaced(\"1 second\") }),\n Effect.exit,\n Effect.andThen(read),\n Effect.as(true),\n Effect.timeoutOrElse({ duration: releaseDeadline, orElse: () => Effect.succeed(false) }),\n // The reads are retried until the deadline, so a failure here is the same unconfirmed end.\n Effect.orElseSucceed(() => false),\n );\n\n if (!confirmed)\n return new Supervisor.Unconfirmed({\n detail: `Session ${id}: ${last} ${Duration.format(releaseDeadline)} after its release`,\n });\n if (settle !== undefined) yield* Effect.sleep(settle);\n\n return new Supervisor.Settled();\n }).pipe(\n Effect.tap((released) => Effect.annotateCurrentSpan({ released: released._tag })),\n Effect.withSpan(\n \"Browserbase.release\",\n { attributes: { session: id, settle: settle !== undefined } },\n { captureStackTrace: false },\n ),\n Effect.uninterruptible,\n );\n\n/** A search for the sessions with `value` under the user metadata key `label`. */\nconst labelled = (label: string, value: string) => `user_metadata['${label}']:'${value}'`;\n\n/**\n * The sessions a search finds that have not ended. Pending ones are listed first, since one listed\n * as pending may be running by the second query.\n */\nconst unended = (client: Service, query: string) =>\n Effect.forEach([\"PENDING\", \"RUNNING\"], (status) => client.listSessions({ status, query })).pipe(\n Effect.map((found) => [\n ...new Map(found.flat().map((session) => [session.id, session])).values(),\n ]),\n );\n\n/**\n * End the sessions and confirm they ended; then wait `settle`, if given, for the last save to land.\n * One still running at its release's deadline makes the outcome `Unconfirmed`.\n */\nconst endAll = (\n client: Service,\n sessions: ReadonlyArray<string>,\n settle: Duration.Duration | undefined,\n) =>\n Effect.forEach(sessions, (session) => confirm(client, session, undefined), {\n concurrency: 4,\n }).pipe(\n Effect.flatMap((outcomes) => {\n const unconfirmed = outcomes.find((outcome) => outcome._tag === \"Unconfirmed\");\n\n return unconfirmed === undefined\n ? Effect.sleep(settle ?? Duration.zero).pipe(\n Effect.as<Supervisor.Released>(new Supervisor.Settled()),\n )\n : Effect.succeed<Supervisor.Released>(unconfirmed);\n }),\n );\n\n/**\n * End the session a create may have made though its answer was lost, found in any state by the\n * create's own label, and then wait `settle`, if given, for its save. Browserbase can list a new\n * session late, so it is looked for again, more and more seldom, until it is found or\n * `orphanSearch` has passed. A search Browserbase never answered is `Unconfirmed`, as is a session\n * still running at its release's deadline.\n */\nconst endOrphan = (client: Service, nonce: string, settle: Duration.Duration | undefined) =>\n Effect.gen(function* () {\n let answered = false;\n\n const found = yield* client.listSessions({ query: labelled(createLabel, nonce) }).pipe(\n Effect.tap(() =>\n Effect.sync(() => {\n answered = true;\n }),\n ),\n Effect.retry(Schedule.exponential(\"1 second\")),\n Effect.repeat({\n schedule: Schedule.exponential(\"1 second\"),\n until: (sessions) => sessions.length > 0,\n }),\n Effect.timeoutOption(orphanSearch),\n );\n\n if (Option.isNone(found) && !answered)\n return new Supervisor.Unconfirmed({\n detail: `Browserbase did not answer a search for it within ${Duration.format(orphanSearch)}`,\n });\n const running = Option.getOrElse(found, () => []).filter((session) => !ended(session));\n\n return yield* endAll(\n client,\n running.map((session) => session.id),\n settle,\n );\n });\n\n/**\n * Hold the stored context through the lease, as its only writer, until the scope closes or the\n * session's end is known; the hold goes once, saying how this writer leaves the context.\n */\nconst holdContext = Effect.fnUntraced(function* (\n client: Service,\n lease: ContextLease[\"Service\"],\n id: string,\n settle: Duration.Duration,\n) {\n const scope = yield* Scope.fork(yield* Effect.scope);\n\n // A second writer waits here for the first one's whole session and the save after it.\n const hold = yield* lease\n .hold(id)\n .pipe(\n Scope.provide(scope),\n Effect.withSpan(\"Browserbase.holdContext\", {}, { captureStackTrace: false }),\n );\n\n // Whether a session that saves to the context may run, as this writer would leave it now.\n let unsettled = hold.unsettled;\n\n const set = (now: boolean) =>\n Effect.sync(() => {\n unsettled = now;\n });\n\n yield* Scope.addFinalizer(\n scope,\n Effect.suspend(() => hold.leave(unsettled)),\n );\n\n const letGo = (now: boolean) => set(now).pipe(Effect.andThen(Scope.close(scope, Exit.void)));\n\n /** End the context's sessions but `except`, found by the label `open` gives them. */\n const end = (except: ReadonlyArray<string>) =>\n unended(client, labelled(contextLabel, id)).pipe(\n Effect.flatMap((found) =>\n endAll(\n client,\n found.map((session) => session.id).filter((session) => !except.includes(session)),\n settle,\n ),\n ),\n Effect.onExit((exit) => set(!(Exit.isSuccess(exit) && exit.value._tag === \"Settled\"))),\n );\n\n const refuse = (outcome: Supervisor.Released) =>\n outcome._tag === \"Settled\"\n ? Effect.void\n : Effect.fail(new ContextHeld({ context: id, detail: outcome.detail }));\n\n return {\n end,\n /**\n * End the sessions, but `except`, that a writer before may have left saving to the context,\n * failing with `ContextHeld` while they can't be confirmed ended.\n */\n clear: (except: ReadonlyArray<string>) =>\n Effect.suspend(() => (unsettled ? Effect.flatMap(end(except), refuse) : Effect.void)),\n /** A session that saves to the context runs from now. */\n writing: set(true),\n /** How the writer's session ended: unconfirmed, it may still save to the context. */\n released: (outcome: Supervisor.Released) => letGo(outcome._tag === \"Unconfirmed\"),\n /** How ending the session a lost create may have made went: unconfirmed, the open fails. */\n lost: (outcome: Supervisor.Released) =>\n letGo(outcome._tag === \"Unconfirmed\").pipe(Effect.andThen(refuse(outcome))),\n /** The writer's session runs on past its scope, saving to the context when it ends. */\n kept: letGo(true),\n };\n});\n\n/** A create that failed so may still have made its session: its answer is lost or unreadable. */\nconst mayHaveCreated = (error: BrowserbaseError) =>\n error.reason._tag === \"Transport\" ||\n error.reason._tag === \"Decode\" ||\n (error.reason._tag === \"Status\" && (error.reason.status >= 500 || error.reason.status === 408));\n\n/** A create's own nonce: two random draws, which no other create draws in practice. */\nconst nonce = Effect.map(Effect.all([Random.nextInt, Random.nextInt]), (draws) =>\n draws.map((draw) => Math.abs(draw).toString(36)).join(\"-\"),\n);\n\n/**\n * The create request, labelled with its own nonce, a persisting session with its context too, so\n * either can be found, and a kept one with what it is kept under, kept alive past disconnecting.\n */\nconst withLabels = (\n session: SessionOptions | undefined,\n own: string,\n context: string | undefined,\n keep: string | undefined,\n) => ({\n ...session,\n ...(keep === undefined ? {} : { keepAlive: true }),\n userMetadata: {\n ...session?.userMetadata,\n [createLabel]: own,\n ...(context === undefined ? {} : { [contextLabel]: context }),\n ...(keep === undefined ? {} : { [keepLabel]: keep }),\n },\n});\n\n/**\n * A release by the browser's owner: it closes the browser first, so that whatever fails then, a\n * capture's reader or a call in flight, says the session was released, and not that the\n * connection Browserbase cuts as the session ends was lost.\n */\nconst releasing = (browser: Scope.Closeable, end: Effect.Effect<Supervisor.Released>) =>\n Scope.close(browser, Exit.void).pipe(Effect.andThen(end));\n\n/**\n * A browser over the session's DevTools address, its pages' screencasts on a capture connection of\n * their own. A DevTools server's HTTP address, as a local Chromium gives in tests, keeps them on\n * each page's own session: there the connection is loopback, and fast. A session that has ended\n * fails `Closed` by the session, with no connect.\n */\nconst connect = Effect.fnUntraced(function* (\n operation: string,\n session: Session,\n options: Options,\n) {\n const endpoint = session.connectUrl;\n\n if (ended(session))\n return yield* new BrowserError({\n operation,\n reason: new Closed({ cause: \"session\" }),\n dispatched: false,\n });\n if (endpoint === undefined)\n return yield* new BrowserbaseError({\n operation,\n reason: new Decode({ detail: `session ${session.id} has no connectUrl` }),\n });\n const apart = options.captureConnection !== false && /^wss?:/i.test(Redacted.value(endpoint));\n\n return yield* Cdp.open({\n ...options,\n endpoint,\n id: session.id,\n provider: \"browserbase\",\n expiresAt: Option.getOrUndefined(DateTime.make(session.expiresAt)),\n capture: apart ? yield* CaptureConnection.make(endpoint) : undefined,\n });\n});\n\n/** How a supervisor keeps its sessions past its scope: under `name`, adopting one first if `adopt`. */\ninterface Keeping {\n readonly name: string;\n readonly adopt: boolean;\n}\n\nconst keepName = /^[\\w.:-]{1,64}$/;\n\nconst newestFirst = (sessions: ReadonlyArray<Session>) => {\n const created = (session: Session) =>\n Option.getOrElse(Option.map(DateTime.make(session.createdAt), DateTime.toEpochMillis), () => 0);\n\n return sessions.toSorted((a, b) => created(b) - created(a));\n};\n\n/**\n * The newest session kept under `name` that saves where this open would, to adopt. Every other\n * session kept under it is to end, since nothing else adopts it: those that save to this open's\n * context are its writers, for the context's hold to end, as `writers` says, and the rest end here.\n */\nconst adoptable = Effect.fnUntraced(function* (\n client: Service,\n name: string,\n persisting: string | undefined,\n) {\n const [newest, ...older] = newestFirst(yield* unended(client, labelled(keepLabel, name)));\n const fits = newest !== undefined && newest.userMetadata?.[contextLabel] === persisting;\n const others = [...(fits || newest === undefined ? [] : [newest]), ...older];\n\n const writes = (session: Session) =>\n persisting !== undefined && session.userMetadata?.[contextLabel] === persisting;\n\n const rest = others.filter((session) => !writes(session));\n\n if (rest.length > 0) {\n const outcome = yield* endAll(\n client,\n rest.map((session) => session.id),\n undefined,\n );\n\n yield* Effect.annotateCurrentSpan({ endedKept: rest.length, endedKeptAs: outcome._tag });\n }\n\n return { adoptee: fits ? newest : undefined, writers: others.some(writes) };\n});\n\n/**\n * Open a browser on a new session, or, when keeping, adopt one a supervisor kept before. A kept\n * session's scope only disconnects, unless it closes on a failure: `release` ends it.\n */\nconst start = Effect.fnUntraced(function* (options: Options, keeping: Keeping | undefined) {\n const client = yield* BrowserbaseClient;\n const lease = yield* ContextLease;\n const reporting = yield* Effect.serviceOption(Supervisor.Releasing);\n\n const report = (outcome: Supervisor.Released) =>\n Option.isSome(reporting) ? reporting.value.released(outcome) : Effect.void;\n\n const context = options.session?.browserSettings?.context;\n const persisting = context?.persist === true ? context.id : undefined;\n const local = yield* Scope.fork(yield* Effect.scope);\n const settle = Duration.fromInputUnsafe(options.contextSettle ?? Duration.seconds(10));\n\n return yield* Effect.gen(function* () {\n if (keeping !== undefined && !keepName.test(keeping.name))\n return yield* new BrowserbaseError({\n operation: \"supervise\",\n reason: new InvalidRequest({\n detail: `keep must be 1 to 64 letters, digits, \"_\", \".\", \":\" or \"-\"`,\n }),\n });\n\n const writing =\n persisting === undefined ? undefined : yield* holdContext(client, lease, persisting, settle);\n\n const adoption = keeping?.adopt\n ? yield* adoptable(client, keeping.name, persisting)\n : undefined;\n\n const adopted = adoption?.adoptee;\n\n // Another writer kept under the name may still save to the context: clear it as any other.\n if (adoption?.writers === true) yield* writing?.writing ?? Effect.void;\n yield* writing?.clear(adopted === undefined ? [] : [adopted.id]) ?? Effect.void;\n const connected = yield* Scope.fork(local);\n const own = yield* nonce;\n\n // Releasing ends the session; leaving, as a kept session's scope does, only disconnects.\n const ending = (session: Session) =>\n Effect.gen(function* () {\n let asked = false;\n\n const release = yield* Effect.cached(\n Effect.suspend(() => {\n asked = true;\n\n return releasing(connected, confirm(client, session.id, writing && settle)).pipe(\n Effect.tap((outcome) => writing?.released(outcome) ?? Effect.void),\n );\n }),\n );\n\n const leave = Effect.suspend(() =>\n asked\n ? Effect.void\n : Scope.close(connected, Exit.void).pipe(Effect.andThen(writing?.kept ?? Effect.void)),\n );\n\n return { session, release, leave };\n });\n\n const made = yield* Effect.acquireRelease(\n Effect.gen(function* () {\n const session =\n adopted === undefined\n ? yield* client.createSession(\n withLabels(options.session, own, persisting, keeping?.name),\n )\n : yield* client.getSession(adopted.id);\n\n yield* writing?.writing ?? Effect.void;\n\n return yield* ending(session);\n }),\n ({ release, leave }, exit) =>\n keeping !== undefined && Exit.isSuccess(exit)\n ? leave\n : release.pipe(\n Effect.flatMap((outcome) => (Exit.isFailure(exit) ? report(outcome) : Effect.void)),\n ),\n ).pipe(\n // A session nobody can see bills until its timeout, and one that saves to the context would\n // write beside the next writer: end it, found by its create's own label.\n Effect.tapError((error) =>\n adopted === undefined && mayHaveCreated(error)\n ? endOrphan(client, own, writing && settle).pipe(\n Effect.tap(report),\n Effect.flatMap((outcome) => writing?.lost(outcome) ?? Effect.void),\n )\n : Effect.void,\n ),\n );\n\n const { session, release } = made;\n\n yield* Effect.annotateCurrentSpan({\n session: session.id,\n region: session.region,\n adopted: adopted !== undefined,\n });\n\n const browser = yield* connect(\n adopted === undefined ? \"open\" : \"attach\",\n session,\n options,\n ).pipe(Scope.provide(connected));\n\n return { browser, session, release } satisfies Hosted;\n }).pipe(\n Scope.provide(local),\n Effect.onError((cause) => Scope.close(local, Exit.failCause(cause))),\n );\n});\n\n/**\n * Create a session and open a `Browser` on it, for as long as the scope is open. If opening\n * fails, the session and context are released then, so a retry in the same scope can take them.\n * A persisting open holds its context through the `ContextLease`; a session that may still save\n * to it, as one whose release was left `Unconfirmed` or whose create's answer was lost, is ended\n * first, and the open fails with `ContextHeld` while that can't be confirmed. A lost create's own\n * open looks for its session by the create's nonce, within `orphanSearch`, ends it, then fails with\n * the create's error. `release` disconnects the browser before it asks Browserbase to end the\n * session, so what fails meanwhile says it was released.\n */\nexport const open = Effect.fn(\"Browserbase.open\")(function* (options: Options = {}) {\n return yield* start(options, undefined);\n});\n\n/**\n * Open a `Browser` on a session that already runs, such as a `keepAlive` session another process\n * opened. This is resume: its pages keep their ids, their CDP target ids, so `browser.page(id)`\n * finds a page stored before. Closing the scope disconnects and leaves the session running;\n * `release` ends it. A session that has ended fails `Closed` by the session. It holds no context.\n */\nexport const attach = Effect.fn(\"Browserbase.attach\")(function* (\n sessionId: string,\n options: Options = {},\n) {\n const client = yield* BrowserbaseClient;\n const session = yield* client.getSession(sessionId);\n\n yield* Effect.annotateCurrentSpan({ session: session.id, region: session.region });\n\n const connected = yield* Scope.fork(yield* Effect.scope);\n const browser = yield* connect(\"attach\", session, options).pipe(Scope.provide(connected));\n\n const release = yield* Effect.cached(\n releasing(connected, confirm(client, session.id, undefined)),\n );\n\n return { browser, session, release } satisfies Hosted;\n});\n\n/**\n * End a stored context's sessions, the ones `open` labelled as writing to it, and let the context\n * go once they are confirmed ended and its save has settled. `open` does this itself when a writer\n * before it may still run; `reconcile` does it without opening, as for sessions another process\n * left running. It holds the context through the `ContextLease`, so it waits for a writer. A\n * session still running at the deadline makes it `Unconfirmed`, and leaves the context unsettled,\n * as a failure does.\n */\nexport const reconcile = Effect.fn(\"Browserbase.reconcile\")(function* (\n contextId: string,\n options: { readonly contextSettle?: Duration.Input | undefined } = {},\n) {\n const client = yield* BrowserbaseClient;\n const lease = yield* ContextLease;\n const settle = Duration.fromInputUnsafe(options.contextSettle ?? Duration.seconds(10));\n\n // Reading the context first refuses an id that is not one before it reaches the query.\n yield* client.getContext(contextId);\n const hold = yield* holdContext(client, lease, contextId, settle);\n\n return yield* hold.end([]);\n}, Effect.scoped);\n\n/**\n * Read a stored context back, as a login: a session that loads it and saves nothing runs `check`\n * on its browser, and is released. The context is held through the `ContextLease` meanwhile, so\n * the read never runs beside a writer, which a site could sign out, and it reads what the last\n * writer saved, once that save settled. A session a writer before may have left saving to it is\n * ended first, as for `open`.\n */\nexport const verifyContext = Effect.fn(\"Browserbase.verifyContext\")(function* <A, E, R>(\n contextId: string,\n check: (browser: Browser.Service) => Effect.Effect<A, E, R>,\n options: Options = {},\n) {\n const client = yield* BrowserbaseClient;\n const lease = yield* ContextLease;\n const settle = Duration.fromInputUnsafe(options.contextSettle ?? Duration.seconds(10));\n const reading = yield* holdContext(client, lease, contextId, settle);\n\n yield* reading.clear([]);\n\n const { browser } = yield* start(\n {\n ...options,\n session: {\n ...options.session,\n browserSettings: {\n ...options.session?.browserSettings,\n context: { id: contextId, persist: false },\n },\n },\n },\n undefined,\n );\n\n return yield* check(browser);\n}, Effect.scoped);\n\nexport interface SuperviseOptions<A = Session, E = never, R = never>\n extends\n Options,\n Pick<\n Supervisor.Options<\n BrowserError | BrowserbaseError | ContextHeld | ContextRefused | E,\n Scope.Scope | BrowserbaseClient | ContextLease | R,\n A\n >,\n \"reopen\" | \"rotateBefore\" | \"waitTimeout\" | \"handover\" | \"admit\" | \"definite\"\n > {\n /**\n * Keep the session past the supervisor's scope, under this name: 1 to 64 letters, digits, `_`,\n * `.`, `:` or `-`. Each session is created with `keepAlive` and labelled `keptAs: <keep>` in its\n * user metadata. Closing the scope only disconnects the current one, published as `Kept`, and\n * the first generation of the next `supervise` under the same name adopts it, with its pages,\n * rather than creating a session; other sessions kept under it are ended. `retire` releases. A\n * kept session bills until it is adopted and released, or until its timeout ends it.\n */\n readonly keep?: string | undefined;\n /** Build the generation's value in its scope. Without a builder, its value is its Session. */\n readonly build?: ((hosted: Hosted) => Effect.Effect<A, E, R>) | undefined;\n}\n\n/**\n * No new try mends a refused key, request, id or context policy. A context held temporarily is\n * not among them, since each try can take its lease and end its sessions again.\n */\nconst refused = (error: unknown) =>\n Schema.is(ContextRefused)(error) ||\n (Schema.is(BrowserbaseError)(error) && !isTransient(error) && error.reason._tag !== \"Decode\");\n\n/**\n * Keep Browserbase sessions open as `Supervisor` generations, each a new session made from\n * `session`. Sessions that persist to a stored context are exclusive: a rotation releases the\n * current one, and its context's save settles, before the next one opens. An open Browserbase\n * refused, as for a bad key or an invalid request, is `Down` at once. With `keep`, closing the\n * scope leaves the current session running for the next `supervise` under that name to adopt.\n */\nexport function supervise<A, E, R>(\n options: SuperviseOptions<A, E, R> & {\n readonly build: (hosted: Hosted) => Effect.Effect<A, E, R>;\n },\n): Effect.Effect<\n Supervisor.Supervisor<A>,\n never,\n Scope.Scope | BrowserbaseClient | ContextLease | Exclude<R, Scope.Scope>\n>;\n\nexport function supervise<A = Session, E = never, R = never>(\n options?: SuperviseOptions<A, E, R>,\n): Effect.Effect<\n Supervisor.Supervisor<A | Session>,\n never,\n Scope.Scope | BrowserbaseClient | ContextLease | Exclude<R, Scope.Scope>\n>;\n\nexport function supervise<A = Session, E = never, R = never>(\n options: SuperviseOptions<A, E, R> = {},\n) {\n return Effect.suspend(() => {\n const { keep } = options;\n // Only the first generation adopts a kept session: a later one would find its own.\n let opened = false;\n\n return Supervisor.make({\n open: Effect.gen(function* () {\n const hosted = yield* start(\n options,\n keep === undefined ? undefined : { name: keep, adopt: !opened },\n );\n\n opened = true;\n // The generation owns resources acquired by build, including on failure or cancellation.\n const value = options.build === undefined ? hosted.session : yield* options.build(hosted);\n\n return { ...hosted, value };\n }).pipe(Effect.withSpan(\"Browserbase.open\", {}, { captureStackTrace: false })),\n exclusive: options.session?.browserSettings?.context?.persist === true,\n keep: keep !== undefined,\n reopen: options.reopen,\n admit: options.admit,\n definite: (error) => refused(error) || options.definite?.(error) === true,\n rotateBefore: options.rotateBefore,\n waitTimeout: options.waitTimeout,\n handover: options.handover,\n });\n });\n}\n\nexport const layer = (\n options: Options = {},\n): Layer.Layer<\n Browser.Browser,\n BrowserError | BrowserbaseError | ContextHeld | ContextRefused,\n BrowserbaseClient | ContextLease\n> =>\n Layer.effect(\n Browser.Browser,\n Effect.map(open(options), ({ browser }) => browser),\n );\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { t as BrowserbaseError } from "./BrowserbaseError-D1EOrLNc.mjs";
2
2
  import { f as Session, n as BrowserbaseClient, p as SessionOptions } from "./BrowserbaseClient-CtAQ2rg4.mjs";
3
- import { ContextHeld, ContextLease } from "./ContextLease.mjs";
3
+ import { ContextHeld, ContextLease, ContextRefused } from "./ContextLease.mjs";
4
4
  import { Duration, Effect, Layer, Scope } from "effect";
5
5
  import * as Browser from "effect-browser/Browser";
6
6
  import { BrowserError } from "effect-browser/BrowserError";
@@ -49,7 +49,7 @@ export declare const open: (options?: Options | undefined) => Effect.Effect<{
49
49
  browser: Browser.Service;
50
50
  session: Session;
51
51
  release: Effect.Effect<Supervisor.Settled | Supervisor.Unconfirmed, never, never>;
52
- }, BrowserError | BrowserbaseError | ContextHeld, BrowserbaseClient | ContextLease | Scope.Scope>;
52
+ }, BrowserError | BrowserbaseError | ContextHeld | ContextRefused, BrowserbaseClient | ContextLease | Scope.Scope>;
53
53
  /**
54
54
  * Open a `Browser` on a session that already runs, such as a `keepAlive` session another process
55
55
  * opened. This is resume: its pages keep their ids, their CDP target ids, so `browser.page(id)`
@@ -71,7 +71,7 @@ export declare const attach: (sessionId: string, options?: Options | undefined)
71
71
  */
72
72
  export declare const reconcile: (contextId: string, options?: {
73
73
  readonly contextSettle?: Duration.Input | undefined;
74
- } | undefined) => Effect.Effect<Supervisor.Settled | Supervisor.Unconfirmed, BrowserbaseError | ContextHeld, BrowserbaseClient | ContextLease>;
74
+ } | undefined) => Effect.Effect<Supervisor.Settled | Supervisor.Unconfirmed, BrowserbaseError | ContextHeld | ContextRefused, BrowserbaseClient | ContextLease>;
75
75
  /**
76
76
  * Read a stored context back, as a login: a session that loads it and saves nothing runs `check`
77
77
  * on its browser, and is released. The context is held through the `ContextLease` meanwhile, so
@@ -79,8 +79,8 @@ export declare const reconcile: (contextId: string, options?: {
79
79
  * writer saved, once that save settled. A session a writer before may have left saving to it is
80
80
  * ended first, as for `open`.
81
81
  */
82
- export declare const verifyContext: <A, E, R>(contextId: string, check: (browser: Browser.Service) => Effect.Effect<A, E, R>, options?: Options | undefined) => Effect.Effect<A, E | BrowserError | BrowserbaseError | ContextHeld, BrowserbaseClient | ContextLease | Exclude<R, Scope.Scope>>;
83
- export interface SuperviseOptions<A = Session, E = never, R = never> extends Options, Pick<Supervisor.Options<BrowserError | BrowserbaseError | ContextHeld | E, BrowserbaseClient | ContextLease | R, A>, "reopen" | "rotateBefore" | "waitTimeout" | "handover"> {
82
+ export declare const verifyContext: <A, E, R>(contextId: string, check: (browser: Browser.Service) => Effect.Effect<A, E, R>, options?: Options | undefined) => Effect.Effect<A, E | BrowserError | BrowserbaseError | ContextHeld | ContextRefused, BrowserbaseClient | ContextLease | Exclude<R, Scope.Scope>>;
83
+ export interface SuperviseOptions<A = Session, E = never, R = never> extends Options, Pick<Supervisor.Options<BrowserError | BrowserbaseError | ContextHeld | ContextRefused | E, Scope.Scope | BrowserbaseClient | ContextLease | R, A>, "reopen" | "rotateBefore" | "waitTimeout" | "handover" | "admit" | "definite"> {
84
84
  /**
85
85
  * Keep the session past the supervisor's scope, under this name: 1 to 64 letters, digits, `_`,
86
86
  * `.`, `:` or `-`. Each session is created with `keepAlive` and labelled `keptAs: <keep>` in its
@@ -104,7 +104,7 @@ export declare function supervise<A, E, R>(options: SuperviseOptions<A, E, R> &
104
104
  readonly build: (hosted: Hosted) => Effect.Effect<A, E, R>;
105
105
  }): Effect.Effect<Supervisor.Supervisor<A>, never, Scope.Scope | BrowserbaseClient | ContextLease | Exclude<R, Scope.Scope>>;
106
106
  export declare function supervise<A = Session, E = never, R = never>(options?: SuperviseOptions<A, E, R>): Effect.Effect<Supervisor.Supervisor<A | Session>, never, Scope.Scope | BrowserbaseClient | ContextLease | Exclude<R, Scope.Scope>>;
107
- export declare const layer: (options?: Options) => Layer.Layer<Browser.Browser, BrowserError | BrowserbaseError | ContextHeld, BrowserbaseClient | ContextLease>;
107
+ export declare const layer: (options?: Options) => Layer.Layer<Browser.Browser, BrowserError | BrowserbaseError | ContextHeld | ContextRefused, BrowserbaseClient | ContextLease>;
108
108
  //#endregion
109
109
  export { Browserbase_d_exports as t };
110
110
  //# sourceMappingURL=Browserbase.d.mts.map
@@ -1,3 +1,3 @@
1
1
  import "./ContextLease.mjs";
2
- import { a as reconcile, i as open, n as attach, o as supervise, r as layer, s as verifyContext } from "./Browserbase-CaPKwEY9.mjs";
2
+ import { a as reconcile, i as open, n as attach, o as supervise, r as layer, s as verifyContext } from "./Browserbase-COF_pYa8.mjs";
3
3
  export { attach, layer, open, reconcile, supervise, verifyContext };
@@ -1,6 +1,6 @@
1
1
  import { Context, Effect, Layer, Schema, Scope } from "effect";
2
2
  declare namespace ContextLease_d_exports {
3
- export { ContextHeld, ContextLease, Hold, Service, layer };
3
+ export { ContextHeld, ContextLease, ContextRefused, Hold, Service, layer };
4
4
  }
5
5
  declare const ContextHeld_base: Schema.Class<ContextHeld, Schema.TaggedStruct<"ContextHeld", {
6
6
  readonly context: Schema.String;
@@ -14,6 +14,14 @@ declare const ContextHeld_base: Schema.Class<ContextHeld, Schema.TaggedStruct<"C
14
14
  export declare class ContextHeld extends ContextHeld_base {
15
15
  get message(): string;
16
16
  }
17
+ declare const ContextRefused_base: Schema.Class<ContextRefused, Schema.TaggedStruct<"ContextRefused", {
18
+ readonly context: Schema.String;
19
+ readonly detail: Schema.String;
20
+ }>, import("effect/Cause").YieldableError>;
21
+ /** The lease refuses this writer outright; retrying cannot change its policy. */
22
+ export declare class ContextRefused extends ContextRefused_base {
23
+ get message(): string;
24
+ }
17
25
  /** A writer's hold on a stored context, for the scope `hold` was given. */
18
26
  export interface Hold {
19
27
  /** Whether a session that saves to the context may still run, as the writer before left it. */
@@ -24,9 +32,10 @@ export interface Hold {
24
32
  export interface Service {
25
33
  /**
26
34
  * Hold the context as its only writer until the scope closes, waiting while another holds it.
27
- * It fails with `ContextHeld` when the lease cannot be taken, as when its own store is down.
35
+ * It fails with `ContextHeld` when the lease cannot be taken, as when its own store is down,
36
+ * or `ContextRefused` when this writer is forbidden and another try cannot help.
28
37
  */
29
- readonly hold: (context: string) => Effect.Effect<Hold, ContextHeld, Scope.Scope>;
38
+ readonly hold: (context: string) => Effect.Effect<Hold, ContextHeld | ContextRefused, Scope.Scope>;
30
39
  }
31
40
  declare const ContextLease_base: Context.ServiceClass<ContextLease, "effect-browserbase/ContextLease", Service>;
32
41
  export declare class ContextLease extends ContextLease_base {}
@@ -22,6 +22,7 @@ import { Context, Effect, Layer, Schema, Semaphore } from "effect";
22
22
  var ContextLease_exports = /* @__PURE__ */ __exportAll({
23
23
  ContextHeld: () => ContextHeld,
24
24
  ContextLease: () => ContextLease,
25
+ ContextRefused: () => ContextRefused,
25
26
  layer: () => layer
26
27
  });
27
28
  /**
@@ -37,6 +38,15 @@ var ContextHeld = class extends Schema.TaggedError()("ContextHeld", {
37
38
  return `context ${this.context} is held: ${this.detail}`;
38
39
  }
39
40
  };
41
+ /** The lease refuses this writer outright; retrying cannot change its policy. */
42
+ var ContextRefused = class extends Schema.TaggedError()("ContextRefused", {
43
+ context: Schema.String,
44
+ detail: Schema.String
45
+ }) {
46
+ get message() {
47
+ return `context ${this.context} is refused: ${this.detail}`;
48
+ }
49
+ };
40
50
  var ContextLease = class extends Context.Service()("effect-browserbase/ContextLease") {};
41
51
  /**
42
52
  * The lease within this process: one writer at a time for each stored context. A context it has
@@ -75,6 +85,6 @@ const layer = Layer.sync(ContextLease, () => {
75
85
  }) });
76
86
  });
77
87
  //#endregion
78
- export { ContextHeld, ContextLease, layer, ContextLease_exports as t };
88
+ export { ContextHeld, ContextLease, ContextRefused, layer, ContextLease_exports as t };
79
89
 
80
90
  //# sourceMappingURL=ContextLease.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ContextLease.mjs","names":[],"sources":["../src/ContextLease.ts"],"sourcesContent":["/**\n * Who may write a stored context. A session that persists to a context saves to it when the\n * session ends, so two at once can lose one's changes. `Browserbase.open` holds a context through\n * its `ContextLease` from before it creates a persisting session until that session has ended and\n * its save has settled, and the next writer waits. `verifyContext` and `reconcile` hold it too.\n *\n * The lease is a port. `layer` holds contexts within the process that builds it. An application\n * whose writers run in several processes provides its own, such as an advisory lock in its\n * database, and so excludes them all.\n *\n * A hold also passes on how the writer before left the context: `unsettled` while a session that\n * saves to it may still run, as when that writer's release was left unconfirmed, its create's answer\n * was lost, or it kept its session past its scope. The next writer then ends the context's sessions\n * before it writes. A writer says how it leaves the context once, as it lets the hold go; a hold\n * that never says, as when its process ends first, must read as `unsettled` to the next.\n *\n * @since 0.3.0\n */\nimport { Context, Effect, Layer, Schema, type Scope, Semaphore } from \"effect\";\n\n/**\n * The stored context could not be held for writing: a session that saves to it may still run, as\n * its sessions could not be confirmed ended, or the lease itself could not be taken. The next try\n * clears it again.\n */\nexport class ContextHeld extends Schema.TaggedError<ContextHeld>()(\"ContextHeld\", {\n context: Schema.String,\n detail: Schema.String,\n}) {\n override get message() {\n return `context ${this.context} is held: ${this.detail}`;\n }\n}\n\n/** A writer's hold on a stored context, for the scope `hold` was given. */\nexport interface Hold {\n /** Whether a session that saves to the context may still run, as the writer before left it. */\n readonly unsettled: boolean;\n /** Say how this writer leaves the context, once, before the hold goes: the next writer reads it. */\n readonly leave: (unsettled: boolean) => Effect.Effect<void>;\n}\n\nexport interface Service {\n /**\n * Hold the context as its only writer until the scope closes, waiting while another holds it.\n * It fails with `ContextHeld` when the lease cannot be taken, as when its own store is down.\n */\n readonly hold: (context: string) => Effect.Effect<Hold, ContextHeld, Scope.Scope>;\n}\n\nexport class ContextLease extends Context.Service<ContextLease, Service>()(\n \"effect-browserbase/ContextLease\",\n) {}\n\ninterface Entry {\n readonly lock: Semaphore.Semaphore;\n unsettled: boolean;\n /** Its holder and the writers waiting for it. */\n users: number;\n}\n\n/**\n * The lease within this process: one writer at a time for each stored context. A context it has\n * not held is presumed settled, so writers in other processes are the application's to exclude,\n * with a lease of its own. It forgets a context once nobody holds it, or waits for it, and it was\n * left settled.\n */\nexport const layer: Layer.Layer<ContextLease> = Layer.sync(ContextLease, () => {\n const contexts = new Map<string, Entry>();\n\n const enter = (context: string) => {\n const entry = contexts.get(context) ?? {\n lock: Semaphore.makeUnsafe(1),\n unsettled: false,\n users: 0,\n };\n\n entry.users += 1;\n contexts.set(context, entry);\n\n return entry;\n };\n\n const exit = (context: string, entry: Entry) => {\n entry.users -= 1;\n if (entry.users === 0 && !entry.unsettled) contexts.delete(context);\n };\n\n return ContextLease.of({\n hold: (context) =>\n Effect.gen(function* () {\n const entry = yield* Effect.acquireRelease(\n Effect.sync(() => enter(context)),\n (entered) => Effect.sync(() => exit(context, entered)),\n );\n\n // Unless the holder says otherwise, it leaves a session that saves to the context running.\n let leaving = true;\n\n yield* Effect.acquireRelease(\n entry.lock.take(1),\n () =>\n Effect.sync(() => {\n entry.unsettled = leaving;\n }).pipe(Effect.andThen(entry.lock.release(1))),\n { interruptible: true },\n );\n\n return {\n unsettled: entry.unsettled,\n leave: (unsettled) =>\n Effect.sync(() => {\n leaving = unsettled;\n }),\n } satisfies Hold;\n }),\n });\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,IAAa,cAAb,cAAiC,OAAO,YAAyB,CAAC,CAAC,eAAe;CAChF,SAAS,OAAO;CAChB,QAAQ,OAAO;AACjB,CAAC,CAAC,CAAC;CACD,IAAa,UAAU;EACrB,OAAO,WAAW,KAAK,QAAQ,YAAY,KAAK;CAClD;AACF;AAkBA,IAAa,eAAb,cAAkC,QAAQ,QAA+B,CAAC,CACxE,iCACF,CAAC,CAAC,CAAC;;;;;;;AAeH,MAAa,QAAmC,MAAM,KAAK,oBAAoB;CAC7E,MAAM,2BAAW,IAAI,IAAmB;CAExC,MAAM,SAAS,YAAoB;EACjC,MAAM,QAAQ,SAAS,IAAI,OAAO,KAAK;GACrC,MAAM,UAAU,WAAW,CAAC;GAC5B,WAAW;GACX,OAAO;EACT;EAEA,MAAM,SAAS;EACf,SAAS,IAAI,SAAS,KAAK;EAE3B,OAAO;CACT;CAEA,MAAM,QAAQ,SAAiB,UAAiB;EAC9C,MAAM,SAAS;EACf,IAAI,MAAM,UAAU,KAAK,CAAC,MAAM,WAAW,SAAS,OAAO,OAAO;CACpE;CAEA,OAAO,aAAa,GAAG,EACrB,OAAO,YACL,OAAO,IAAI,aAAa;EACtB,MAAM,QAAQ,OAAO,OAAO,eAC1B,OAAO,WAAW,MAAM,OAAO,CAAC,IAC/B,YAAY,OAAO,WAAW,KAAK,SAAS,OAAO,CAAC,CACvD;EAGA,IAAI,UAAU;EAEd,OAAO,OAAO,eACZ,MAAM,KAAK,KAAK,CAAC,SAEf,OAAO,WAAW;GAChB,MAAM,YAAY;EACpB,CAAC,CAAC,CAAC,KAAK,OAAO,QAAQ,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAC/C,EAAE,eAAe,KAAK,CACxB;EAEA,OAAO;GACL,WAAW,MAAM;GACjB,QAAQ,cACN,OAAO,WAAW;IAChB,UAAU;GACZ,CAAC;EACL;CACF,CAAC,EACL,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"ContextLease.mjs","names":[],"sources":["../src/ContextLease.ts"],"sourcesContent":["/**\n * Who may write a stored context. A session that persists to a context saves to it when the\n * session ends, so two at once can lose one's changes. `Browserbase.open` holds a context through\n * its `ContextLease` from before it creates a persisting session until that session has ended and\n * its save has settled, and the next writer waits. `verifyContext` and `reconcile` hold it too.\n *\n * The lease is a port. `layer` holds contexts within the process that builds it. An application\n * whose writers run in several processes provides its own, such as an advisory lock in its\n * database, and so excludes them all.\n *\n * A hold also passes on how the writer before left the context: `unsettled` while a session that\n * saves to it may still run, as when that writer's release was left unconfirmed, its create's answer\n * was lost, or it kept its session past its scope. The next writer then ends the context's sessions\n * before it writes. A writer says how it leaves the context once, as it lets the hold go; a hold\n * that never says, as when its process ends first, must read as `unsettled` to the next.\n *\n * @since 0.3.0\n */\nimport { Context, Effect, Layer, Schema, type Scope, Semaphore } from \"effect\";\n\n/**\n * The stored context could not be held for writing: a session that saves to it may still run, as\n * its sessions could not be confirmed ended, or the lease itself could not be taken. The next try\n * clears it again.\n */\nexport class ContextHeld extends Schema.TaggedError<ContextHeld>()(\"ContextHeld\", {\n context: Schema.String,\n detail: Schema.String,\n}) {\n override get message() {\n return `context ${this.context} is held: ${this.detail}`;\n }\n}\n\n/** The lease refuses this writer outright; retrying cannot change its policy. */\nexport class ContextRefused extends Schema.TaggedError<ContextRefused>()(\"ContextRefused\", {\n context: Schema.String,\n detail: Schema.String,\n}) {\n override get message() {\n return `context ${this.context} is refused: ${this.detail}`;\n }\n}\n\n/** A writer's hold on a stored context, for the scope `hold` was given. */\nexport interface Hold {\n /** Whether a session that saves to the context may still run, as the writer before left it. */\n readonly unsettled: boolean;\n /** Say how this writer leaves the context, once, before the hold goes: the next writer reads it. */\n readonly leave: (unsettled: boolean) => Effect.Effect<void>;\n}\n\nexport interface Service {\n /**\n * Hold the context as its only writer until the scope closes, waiting while another holds it.\n * It fails with `ContextHeld` when the lease cannot be taken, as when its own store is down,\n * or `ContextRefused` when this writer is forbidden and another try cannot help.\n */\n readonly hold: (\n context: string,\n ) => Effect.Effect<Hold, ContextHeld | ContextRefused, Scope.Scope>;\n}\n\nexport class ContextLease extends Context.Service<ContextLease, Service>()(\n \"effect-browserbase/ContextLease\",\n) {}\n\ninterface Entry {\n readonly lock: Semaphore.Semaphore;\n unsettled: boolean;\n /** Its holder and the writers waiting for it. */\n users: number;\n}\n\n/**\n * The lease within this process: one writer at a time for each stored context. A context it has\n * not held is presumed settled, so writers in other processes are the application's to exclude,\n * with a lease of its own. It forgets a context once nobody holds it, or waits for it, and it was\n * left settled.\n */\nexport const layer: Layer.Layer<ContextLease> = Layer.sync(ContextLease, () => {\n const contexts = new Map<string, Entry>();\n\n const enter = (context: string) => {\n const entry = contexts.get(context) ?? {\n lock: Semaphore.makeUnsafe(1),\n unsettled: false,\n users: 0,\n };\n\n entry.users += 1;\n contexts.set(context, entry);\n\n return entry;\n };\n\n const exit = (context: string, entry: Entry) => {\n entry.users -= 1;\n if (entry.users === 0 && !entry.unsettled) contexts.delete(context);\n };\n\n return ContextLease.of({\n hold: (context) =>\n Effect.gen(function* () {\n const entry = yield* Effect.acquireRelease(\n Effect.sync(() => enter(context)),\n (entered) => Effect.sync(() => exit(context, entered)),\n );\n\n // Unless the holder says otherwise, it leaves a session that saves to the context running.\n let leaving = true;\n\n yield* Effect.acquireRelease(\n entry.lock.take(1),\n () =>\n Effect.sync(() => {\n entry.unsettled = leaving;\n }).pipe(Effect.andThen(entry.lock.release(1))),\n { interruptible: true },\n );\n\n return {\n unsettled: entry.unsettled,\n leave: (unsettled) =>\n Effect.sync(() => {\n leaving = unsettled;\n }),\n } satisfies Hold;\n }),\n });\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,IAAa,cAAb,cAAiC,OAAO,YAAyB,CAAC,CAAC,eAAe;CAChF,SAAS,OAAO;CAChB,QAAQ,OAAO;AACjB,CAAC,CAAC,CAAC;CACD,IAAa,UAAU;EACrB,OAAO,WAAW,KAAK,QAAQ,YAAY,KAAK;CAClD;AACF;;AAGA,IAAa,iBAAb,cAAoC,OAAO,YAA4B,CAAC,CAAC,kBAAkB;CACzF,SAAS,OAAO;CAChB,QAAQ,OAAO;AACjB,CAAC,CAAC,CAAC;CACD,IAAa,UAAU;EACrB,OAAO,WAAW,KAAK,QAAQ,eAAe,KAAK;CACrD;AACF;AAqBA,IAAa,eAAb,cAAkC,QAAQ,QAA+B,CAAC,CACxE,iCACF,CAAC,CAAC,CAAC;;;;;;;AAeH,MAAa,QAAmC,MAAM,KAAK,oBAAoB;CAC7E,MAAM,2BAAW,IAAI,IAAmB;CAExC,MAAM,SAAS,YAAoB;EACjC,MAAM,QAAQ,SAAS,IAAI,OAAO,KAAK;GACrC,MAAM,UAAU,WAAW,CAAC;GAC5B,WAAW;GACX,OAAO;EACT;EAEA,MAAM,SAAS;EACf,SAAS,IAAI,SAAS,KAAK;EAE3B,OAAO;CACT;CAEA,MAAM,QAAQ,SAAiB,UAAiB;EAC9C,MAAM,SAAS;EACf,IAAI,MAAM,UAAU,KAAK,CAAC,MAAM,WAAW,SAAS,OAAO,OAAO;CACpE;CAEA,OAAO,aAAa,GAAG,EACrB,OAAO,YACL,OAAO,IAAI,aAAa;EACtB,MAAM,QAAQ,OAAO,OAAO,eAC1B,OAAO,WAAW,MAAM,OAAO,CAAC,IAC/B,YAAY,OAAO,WAAW,KAAK,SAAS,OAAO,CAAC,CACvD;EAGA,IAAI,UAAU;EAEd,OAAO,OAAO,eACZ,MAAM,KAAK,KAAK,CAAC,SAEf,OAAO,WAAW;GAChB,MAAM,YAAY;EACpB,CAAC,CAAC,CAAC,KAAK,OAAO,QAAQ,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAC/C,EAAE,eAAe,KAAK,CACxB;EAEA,OAAO;GACL,WAAW,MAAM;GACjB,QAAQ,cACN,OAAO,WAAW;IAChB,UAAU;GACZ,CAAC;EACL;CACF,CAAC,EACL,CAAC;AACH,CAAC"}
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as BrowserbaseError_exports } from "./BrowserbaseError.mjs";
2
2
  import { t as BrowserbaseClient_exports } from "./BrowserbaseClient.mjs";
3
3
  import { t as ContextLease_exports } from "./ContextLease.mjs";
4
- import { t as Browserbase_exports } from "./Browserbase-CaPKwEY9.mjs";
4
+ import { t as Browserbase_exports } from "./Browserbase-COF_pYa8.mjs";
5
5
  export { Browserbase_exports as Browserbase, BrowserbaseClient_exports as BrowserbaseClient, BrowserbaseError_exports as BrowserbaseError, ContextLease_exports as ContextLease };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "effect-browserbase",
3
- "version": "0.3.0-beta.13",
3
+ "version": "0.3.0-beta.15",
4
4
  "description": "Browserbase for effect-browser: hosted browser sessions, contexts, web search and page fetch.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -58,7 +58,7 @@
58
58
  "@effect/vitest": "4.0.0",
59
59
  "@types/node": "26.1.2",
60
60
  "effect": "4.0.0",
61
- "effect-browser": "0.3.0-beta.13",
61
+ "effect-browser": "0.3.0-beta.15",
62
62
  "playwright-core": "1.63.0",
63
63
  "typescript": "7.0.2",
64
64
  "vite": "npm:@voidzero-dev/vite-plus-core@1.1.0",
@@ -67,7 +67,7 @@
67
67
  },
68
68
  "peerDependencies": {
69
69
  "effect": "~4.0.0",
70
- "effect-browser": "^0.3.0-beta.13",
70
+ "effect-browser": "^0.3.0-beta.15",
71
71
  "playwright-core": "^1.63.0"
72
72
  },
73
73
  "engines": {
@@ -51,7 +51,7 @@ import {
51
51
  type SessionOptions,
52
52
  } from "./BrowserbaseClient.ts";
53
53
  import { BrowserbaseError, Decode, InvalidRequest, isTransient } from "./BrowserbaseError.ts";
54
- import { ContextHeld, ContextLease } from "./ContextLease.ts";
54
+ import { ContextHeld, ContextLease, ContextRefused } from "./ContextLease.ts";
55
55
  import * as CaptureConnection from "./internal/captureConnection.ts";
56
56
 
57
57
  export interface Options extends Browser.Options {
@@ -137,7 +137,7 @@ const confirm = (client: Service, id: string, settle: Duration.Duration | undefi
137
137
 
138
138
  if (!confirmed)
139
139
  return new Supervisor.Unconfirmed({
140
- detail: `${last} ${Duration.format(releaseDeadline)} after its release`,
140
+ detail: `Session ${id}: ${last} ${Duration.format(releaseDeadline)} after its release`,
141
141
  });
142
142
  if (settle !== undefined) yield* Effect.sleep(settle);
143
143
 
@@ -429,6 +429,11 @@ const adoptable = Effect.fnUntraced(function* (
429
429
  const start = Effect.fnUntraced(function* (options: Options, keeping: Keeping | undefined) {
430
430
  const client = yield* BrowserbaseClient;
431
431
  const lease = yield* ContextLease;
432
+ const reporting = yield* Effect.serviceOption(Supervisor.Releasing);
433
+
434
+ const report = (outcome: Supervisor.Released) =>
435
+ Option.isSome(reporting) ? reporting.value.released(outcome) : Effect.void;
436
+
432
437
  const context = options.session?.browserSettings?.context;
433
438
  const persisting = context?.persist === true ? context.id : undefined;
434
439
  const local = yield* Scope.fork(yield* Effect.scope);
@@ -496,13 +501,18 @@ const start = Effect.fnUntraced(function* (options: Options, keeping: Keeping |
496
501
  return yield* ending(session);
497
502
  }),
498
503
  ({ release, leave }, exit) =>
499
- keeping !== undefined && Exit.isSuccess(exit) ? leave : Effect.asVoid(release),
504
+ keeping !== undefined && Exit.isSuccess(exit)
505
+ ? leave
506
+ : release.pipe(
507
+ Effect.flatMap((outcome) => (Exit.isFailure(exit) ? report(outcome) : Effect.void)),
508
+ ),
500
509
  ).pipe(
501
510
  // A session nobody can see bills until its timeout, and one that saves to the context would
502
511
  // write beside the next writer: end it, found by its create's own label.
503
512
  Effect.tapError((error) =>
504
513
  adopted === undefined && mayHaveCreated(error)
505
514
  ? endOrphan(client, own, writing && settle).pipe(
515
+ Effect.tap(report),
506
516
  Effect.flatMap((outcome) => writing?.lost(outcome) ?? Effect.void),
507
517
  )
508
518
  : Effect.void,
@@ -633,11 +643,11 @@ export interface SuperviseOptions<A = Session, E = never, R = never>
633
643
  Options,
634
644
  Pick<
635
645
  Supervisor.Options<
636
- BrowserError | BrowserbaseError | ContextHeld | E,
637
- BrowserbaseClient | ContextLease | R,
646
+ BrowserError | BrowserbaseError | ContextHeld | ContextRefused | E,
647
+ Scope.Scope | BrowserbaseClient | ContextLease | R,
638
648
  A
639
649
  >,
640
- "reopen" | "rotateBefore" | "waitTimeout" | "handover"
650
+ "reopen" | "rotateBefore" | "waitTimeout" | "handover" | "admit" | "definite"
641
651
  > {
642
652
  /**
643
653
  * Keep the session past the supervisor's scope, under this name: 1 to 64 letters, digits, `_`,
@@ -653,11 +663,12 @@ export interface SuperviseOptions<A = Session, E = never, R = never>
653
663
  }
654
664
 
655
665
  /**
656
- * Browserbase refused the request: no new try mends a refused key, request or id. A context held
657
- * is not among them, since each try ends its sessions again.
666
+ * No new try mends a refused key, request, id or context policy. A context held temporarily is
667
+ * not among them, since each try can take its lease and end its sessions again.
658
668
  */
659
669
  const refused = (error: unknown) =>
660
- Schema.is(BrowserbaseError)(error) && !isTransient(error) && error.reason._tag !== "Decode";
670
+ Schema.is(ContextRefused)(error) ||
671
+ (Schema.is(BrowserbaseError)(error) && !isTransient(error) && error.reason._tag !== "Decode");
661
672
 
662
673
  /**
663
674
  * Keep Browserbase sessions open as `Supervisor` generations, each a new session made from
@@ -708,7 +719,8 @@ export function supervise<A = Session, E = never, R = never>(
708
719
  exclusive: options.session?.browserSettings?.context?.persist === true,
709
720
  keep: keep !== undefined,
710
721
  reopen: options.reopen,
711
- definite: refused,
722
+ admit: options.admit,
723
+ definite: (error) => refused(error) || options.definite?.(error) === true,
712
724
  rotateBefore: options.rotateBefore,
713
725
  waitTimeout: options.waitTimeout,
714
726
  handover: options.handover,
@@ -720,7 +732,7 @@ export const layer = (
720
732
  options: Options = {},
721
733
  ): Layer.Layer<
722
734
  Browser.Browser,
723
- BrowserError | BrowserbaseError | ContextHeld,
735
+ BrowserError | BrowserbaseError | ContextHeld | ContextRefused,
724
736
  BrowserbaseClient | ContextLease
725
737
  > =>
726
738
  Layer.effect(
@@ -32,6 +32,16 @@ export class ContextHeld extends Schema.TaggedError<ContextHeld>()("ContextHeld"
32
32
  }
33
33
  }
34
34
 
35
+ /** The lease refuses this writer outright; retrying cannot change its policy. */
36
+ export class ContextRefused extends Schema.TaggedError<ContextRefused>()("ContextRefused", {
37
+ context: Schema.String,
38
+ detail: Schema.String,
39
+ }) {
40
+ override get message() {
41
+ return `context ${this.context} is refused: ${this.detail}`;
42
+ }
43
+ }
44
+
35
45
  /** A writer's hold on a stored context, for the scope `hold` was given. */
36
46
  export interface Hold {
37
47
  /** Whether a session that saves to the context may still run, as the writer before left it. */
@@ -43,9 +53,12 @@ export interface Hold {
43
53
  export interface Service {
44
54
  /**
45
55
  * Hold the context as its only writer until the scope closes, waiting while another holds it.
46
- * It fails with `ContextHeld` when the lease cannot be taken, as when its own store is down.
56
+ * It fails with `ContextHeld` when the lease cannot be taken, as when its own store is down,
57
+ * or `ContextRefused` when this writer is forbidden and another try cannot help.
47
58
  */
48
- readonly hold: (context: string) => Effect.Effect<Hold, ContextHeld, Scope.Scope>;
59
+ readonly hold: (
60
+ context: string,
61
+ ) => Effect.Effect<Hold, ContextHeld | ContextRefused, Scope.Scope>;
49
62
  }
50
63
 
51
64
  export class ContextLease extends Context.Service<ContextLease, Service>()(
@@ -1 +0,0 @@
1
- {"version":3,"file":"Browserbase-CaPKwEY9.mjs","names":["CaptureConnection.make"],"sources":["../src/internal/captureConnection.ts","../src/Browserbase.ts"],"sourcesContent":["/**\n * The capture connection: a second DevTools connection to a session, for its pages' screencasts\n * alone. A frame and its acknowledgement then never wait behind a large message on the\n * connection Playwright drives the pages over, such as an upload or a read's answer: Browserbase\n * refuses compression, and on air those waits stopped the picture for as long as the message took\n * to cross.\n *\n * Raw CDP over the global WebSocket, with no Playwright. A page's session on it sends only the\n * capture's commands, and receives that page's events. The connection opens as the first capture\n * starts and stays until the scope closes, which closes it and waits, bounded, for it to close;\n * one that fails ends every page's session on it, and the next capture opens another.\n */\nimport { Duration, Effect, Option, Redacted, Schema, Semaphore } from \"effect\";\nimport type { CaptureSource } from \"effect-browser/Browser\";\nimport { BrowserError, Failed } from \"effect-browser/BrowserError\";\n\nconst Message = Schema.fromJsonString(\n Schema.Struct({\n id: Schema.optionalKey(Schema.Int),\n sessionId: Schema.optionalKey(Schema.String),\n method: Schema.optionalKey(Schema.String),\n params: Schema.optionalKey(Schema.Unknown),\n result: Schema.optionalKey(Schema.Unknown),\n error: Schema.optionalKey(Schema.Struct({ message: Schema.String })),\n }),\n);\n\nconst Session = Schema.Struct({ sessionId: Schema.String });\n\ntype Listener = Parameters<CaptureSource[\"attach\"]>[1];\n\ninterface Open {\n readonly socket: WebSocket;\n /** Replies awaited, by command id. */\n readonly replies: Map<\n number,\n { readonly resolve: (result: unknown) => void; readonly reject: (error: BrowserError) => void }\n >;\n /** Each attached page's listener, by its session id. */\n readonly sessions: Map<string, Listener>;\n}\n\ntype State =\n | { readonly _tag: \"Idle\" }\n | { readonly _tag: \"Open\"; readonly open: Open }\n | { readonly _tag: \"Closed\" };\n\nconst failure = (detail: string) =>\n new BrowserError({ operation: \"screencast\", reason: new Failed({ detail }), dispatched: false });\n\nconst closing = Duration.seconds(2);\n\n/** The capture connection to the DevTools address `url`, for the scope. */\nexport const make = Effect.fnUntraced(function* (url: Redacted.Redacted<string>) {\n let state: State = { _tag: \"Idle\" };\n let ids = 0;\n const opening = yield* Semaphore.make(1);\n\n // A failure ends every page's session on the connection; the next capture opens another.\n const lose = (open: Open, error: BrowserError) => {\n if (state._tag !== \"Open\" || state.open !== open) return;\n state = { _tag: \"Idle\" };\n for (const reply of open.replies.values()) reply.reject(error);\n for (const listener of open.sessions.values()) listener.lost(error);\n open.replies.clear();\n open.sessions.clear();\n };\n\n const receive = (open: Open, data: unknown) => {\n const decoded = typeof data === \"string\" ? Schema.decodeOption(Message)(data) : Option.none();\n\n if (Option.isNone(decoded))\n return lose(open, failure(\"the capture connection sent a message it could not read\"));\n const { id, sessionId, method, params, result, error } = decoded.value;\n\n if (id !== undefined) {\n const reply = open.replies.get(id);\n\n open.replies.delete(id);\n if (error === undefined) reply?.resolve(result);\n else reply?.reject(failure(error.message));\n } else if (method === undefined) return;\n else if (sessionId !== undefined) open.sessions.get(sessionId)?.event(method, params);\n // The connection's own session announces that a page's session ended.\n else if (method === \"Target.detachedFromTarget\") {\n const detached = Schema.decodeUnknownOption(Session)(params);\n const ended = Option.isSome(detached) ? detached.value.sessionId : \"\";\n const listener = open.sessions.get(ended);\n\n open.sessions.delete(ended);\n listener?.event(method, params);\n }\n };\n\n const send = (\n open: Open,\n method: string,\n params: Record<string, unknown> | undefined,\n sessionId?: string,\n ) => {\n if (state._tag !== \"Open\" || state.open !== open)\n return Promise.reject(failure(\"the capture connection was lost\"));\n const id = ++ids;\n const { promise, resolve, reject } = Promise.withResolvers<unknown>();\n\n open.replies.set(id, { resolve, reject });\n try {\n open.socket.send(JSON.stringify({ id, method, params, sessionId }));\n } catch {\n open.replies.delete(id);\n reject(failure(\"the capture connection could not send\"));\n }\n\n return promise;\n };\n\n const connect = Effect.callback<Open, BrowserError>((resume) => {\n const socket = new WebSocket(Redacted.value(url));\n const open: Open = { socket, replies: new Map(), sessions: new Map() };\n\n const unopened = () => resume(Effect.fail(failure(\"the capture connection did not open\")));\n\n socket.addEventListener(\"close\", unopened, { once: true });\n socket.addEventListener(\n \"open\",\n () => {\n socket.removeEventListener(\"close\", unopened);\n // A scope that closed meanwhile keeps no connection.\n if (state._tag === \"Closed\") {\n socket.close(1000);\n\n return resume(Effect.fail(failure(\"the capture connection is closed\")));\n }\n state = { _tag: \"Open\", open };\n socket.addEventListener(\"close\", () =>\n lose(open, failure(\"the capture connection was lost\")),\n );\n resume(Effect.succeed(open));\n },\n { once: true },\n );\n socket.addEventListener(\"message\", ({ data }: MessageEvent<unknown>) => receive(open, data));\n\n return Effect.sync(() => socket.close(1000));\n });\n\n const current = opening.withPermits(1)(\n Effect.suspend(() =>\n state._tag === \"Open\"\n ? Effect.succeed(state.open)\n : state._tag === \"Closed\"\n ? Effect.fail(failure(\"the capture connection is closed\"))\n : connect,\n ),\n );\n\n const replied = (reply: () => Promise<unknown>) =>\n Effect.tryPromise({\n try: reply,\n catch: (cause) =>\n Schema.is(BrowserError)(cause) ? cause : failure(\"the capture connection failed\"),\n });\n\n const attach: CaptureSource[\"attach\"] = (target, listener) =>\n Effect.gen(function* () {\n const open = yield* current;\n\n const { sessionId } = yield* replied(() =>\n send(open, \"Target.attachToTarget\", { targetId: target, flatten: true }),\n ).pipe(\n Effect.flatMap((result) =>\n Schema.decodeUnknownEffect(Session)(result).pipe(\n Effect.mapError(() => failure(\"the capture connection's attach had no session\")),\n ),\n ),\n );\n\n open.sessions.set(sessionId, listener);\n // Detached as the page's scope closes; a connection that closes detaches every session.\n yield* Effect.addFinalizer(() =>\n Effect.sync(() => {\n if (open.sessions.delete(sessionId))\n void send(open, \"Target.detachFromTarget\", { sessionId }, undefined).catch(\n () => undefined,\n );\n }),\n );\n\n return (method, params) => send(open, method, params, sessionId);\n });\n\n // Closing the scope closes the connection and waits, bounded, until it has closed.\n yield* Effect.addFinalizer(() =>\n Effect.suspend(() => {\n const previous = state;\n\n state = { _tag: \"Closed\" };\n if (previous._tag !== \"Open\") return Effect.void;\n const { socket, replies, sessions } = previous.open;\n\n for (const reply of replies.values()) reply.reject(failure(\"the capture connection closed\"));\n replies.clear();\n sessions.clear();\n\n return Effect.callback<void>((resume) => {\n if (socket.readyState === WebSocket.CLOSED) return resume(Effect.void);\n socket.addEventListener(\"close\", () => resume(Effect.void), { once: true });\n socket.close(1000);\n }).pipe(Effect.timeoutOrElse({ duration: closing, orElse: () => Effect.void }));\n }),\n );\n\n return { attach } satisfies CaptureSource;\n});\n","/**\n * A `Browser` running on Browserbase.\n *\n * `open` creates a session and connects to it over CDP. When its scope closes it disconnects,\n * releases the session and confirms that Browserbase reports it ended, so billing stops then\n * rather than at the session's timeout. `release` does the same sooner and says how it went:\n * `Settled`, or `Unconfirmed` when Browserbase still reported the session running, or could not\n * be asked, at the deadline. Each create carries a nonce of its own in its user metadata, so a\n * session made by a create whose answer was lost is found and ended too, rather than billing\n * unseen until its timeout.\n *\n * A session that persists to a stored context saves to it when the session ends, so two at once\n * can lose one's changes. `open` holds the context through the `ContextLease` the application\n * provides, from before it creates such a session until Browserbase reports the session ended and\n * `contextSettle` has passed, since the save lands later and nothing acknowledges it. A writer that\n * leaves a session that saves to the context possibly running, its release `Unconfirmed`, its\n * create's answer lost or its session kept, leaves the context unsettled: the next writer first ends\n * the context's sessions, which `open` labels in their user metadata, and fails with `ContextHeld`\n * while they can't be confirmed ended. `reconcile` ends them without opening, and `verifyContext`\n * reads a context back under the same hold, from a session that saves nothing.\n *\n * `attach` connects to a session that already runs, as from another process: its pages keep their\n * ids, so a page stored before is found again. `supervise` keeps a session open across losses and\n * session ends, as `Supervisor` generations, and with `keep`, past its own scope, for the next\n * `supervise` to adopt.\n *\n * @since 0.3.0\n */\nimport {\n DateTime,\n Duration,\n Effect,\n Exit,\n Layer,\n Option,\n Random,\n Redacted,\n Schedule,\n Schema,\n Scope,\n} from \"effect\";\nimport * as Browser from \"effect-browser/Browser\";\nimport { BrowserError, Closed } from \"effect-browser/BrowserError\";\nimport * as Cdp from \"effect-browser/Cdp\";\nimport * as Supervisor from \"effect-browser/Supervisor\";\n\nimport {\n BrowserbaseClient,\n type Service,\n type Session,\n type SessionOptions,\n} from \"./BrowserbaseClient.ts\";\nimport { BrowserbaseError, Decode, InvalidRequest, isTransient } from \"./BrowserbaseError.ts\";\nimport { ContextHeld, ContextLease } from \"./ContextLease.ts\";\nimport * as CaptureConnection from \"./internal/captureConnection.ts\";\n\nexport interface Options extends Browser.Options {\n readonly session?: SessionOptions | undefined;\n /** Bound on connecting to the session. Defaults to 30 seconds. */\n readonly connectTimeoutMillis?: number | undefined;\n /**\n * How long a persisting session's context stays held after the session ends, for its save to\n * land. Defaults to 10 seconds, after which hosted checks have read a save back.\n */\n readonly contextSettle?: Duration.Input | undefined;\n /**\n * Run the pages' screencasts on a second connection to the session, which carries nothing else,\n * so that a frame never waits behind a large message, such as an upload or a read's answer, on\n * the connection that drives the page. Defaults to true.\n */\n readonly captureConnection?: boolean | undefined;\n}\n\n/** A browser on a Browserbase session. */\nexport interface Hosted {\n readonly browser: Browser.Service;\n readonly session: Session;\n /**\n * Release the session and confirm it ended, once: `open`'s scope runs it as it closes, while\n * `attach`'s only disconnects. It disconnects `browser` first, which is lost as `released`, so a\n * call in flight or a capture's reader is told so. Asked again, it reports the same outcome.\n */\n readonly release: Effect.Effect<Supervisor.Released>;\n}\n\n/** The user metadata key naming the stored context a persisting session writes to. */\nconst contextLabel = \"persistsContext\";\n\n/** The user metadata key holding each create's own nonce, which finds a session made unseen. */\nconst createLabel = \"createNonce\";\n\n/** The user metadata key naming what a supervisor keeps its sessions under, past its scope. */\nconst keepLabel = \"keptAs\";\n\n/**\n * How long a create whose answer was lost has its session looked for: Browserbase can list a new\n * session late, or still be making it when the client stops waiting.\n */\nconst orphanSearch = Duration.seconds(30);\n\n/** How long a release waits for Browserbase to report the session ended. */\nconst releaseDeadline = Duration.minutes(1);\n\nconst ended = (session: Session) => session.status !== \"PENDING\" && session.status !== \"RUNNING\";\n\n/**\n * End the session and confirm Browserbase reports it ended. The release request and the status\n * reads are each tried again a second apart until the deadline; a session still running then, or\n * one Browserbase could not be asked about, is `Unconfirmed`. Once it has ended, wait `settle`\n * longer, for its context's save to land. It runs to the end once started.\n */\nconst confirm = (client: Service, id: string, settle: Duration.Duration | undefined) =>\n Effect.gen(function* () {\n // What Browserbase last said, for an end it never confirmed.\n let last = \"Browserbase did not answer\";\n\n const heard = (error: BrowserbaseError) => Effect.sync(() => (last = error.message));\n\n const read = client.getSession(id).pipe(\n Effect.tapError(heard),\n Effect.tap((session) => Effect.sync(() => (last = `the session was ${session.status}`))),\n Effect.retry(Schedule.spaced(\"1 second\")),\n Effect.repeat({ until: ended, schedule: Schedule.spaced(\"1 second\") }),\n );\n\n // A release that keeps failing leaves the status reads to tell whether the session ended.\n const confirmed = yield* client.releaseSession(id).pipe(\n Effect.tapError(heard),\n Effect.retry({ while: isTransient, schedule: Schedule.spaced(\"1 second\") }),\n Effect.exit,\n Effect.andThen(read),\n Effect.as(true),\n Effect.timeoutOrElse({ duration: releaseDeadline, orElse: () => Effect.succeed(false) }),\n // The reads are retried until the deadline, so a failure here is the same unconfirmed end.\n Effect.orElseSucceed(() => false),\n );\n\n if (!confirmed)\n return new Supervisor.Unconfirmed({\n detail: `${last} ${Duration.format(releaseDeadline)} after its release`,\n });\n if (settle !== undefined) yield* Effect.sleep(settle);\n\n return new Supervisor.Settled();\n }).pipe(\n Effect.tap((released) => Effect.annotateCurrentSpan({ released: released._tag })),\n Effect.withSpan(\n \"Browserbase.release\",\n { attributes: { session: id, settle: settle !== undefined } },\n { captureStackTrace: false },\n ),\n Effect.uninterruptible,\n );\n\n/** A search for the sessions with `value` under the user metadata key `label`. */\nconst labelled = (label: string, value: string) => `user_metadata['${label}']:'${value}'`;\n\n/**\n * The sessions a search finds that have not ended. Pending ones are listed first, since one listed\n * as pending may be running by the second query.\n */\nconst unended = (client: Service, query: string) =>\n Effect.forEach([\"PENDING\", \"RUNNING\"], (status) => client.listSessions({ status, query })).pipe(\n Effect.map((found) => [\n ...new Map(found.flat().map((session) => [session.id, session])).values(),\n ]),\n );\n\n/**\n * End the sessions and confirm they ended; then wait `settle`, if given, for the last save to land.\n * One still running at its release's deadline makes the outcome `Unconfirmed`.\n */\nconst endAll = (\n client: Service,\n sessions: ReadonlyArray<string>,\n settle: Duration.Duration | undefined,\n) =>\n Effect.forEach(sessions, (session) => confirm(client, session, undefined), {\n concurrency: 4,\n }).pipe(\n Effect.flatMap((outcomes) => {\n const unconfirmed = outcomes.find((outcome) => outcome._tag === \"Unconfirmed\");\n\n return unconfirmed === undefined\n ? Effect.sleep(settle ?? Duration.zero).pipe(\n Effect.as<Supervisor.Released>(new Supervisor.Settled()),\n )\n : Effect.succeed<Supervisor.Released>(unconfirmed);\n }),\n );\n\n/**\n * End the session a create may have made though its answer was lost, found in any state by the\n * create's own label, and then wait `settle`, if given, for its save. Browserbase can list a new\n * session late, so it is looked for again, more and more seldom, until it is found or\n * `orphanSearch` has passed. A search Browserbase never answered is `Unconfirmed`, as is a session\n * still running at its release's deadline.\n */\nconst endOrphan = (client: Service, nonce: string, settle: Duration.Duration | undefined) =>\n Effect.gen(function* () {\n let answered = false;\n\n const found = yield* client.listSessions({ query: labelled(createLabel, nonce) }).pipe(\n Effect.tap(() =>\n Effect.sync(() => {\n answered = true;\n }),\n ),\n Effect.retry(Schedule.exponential(\"1 second\")),\n Effect.repeat({\n schedule: Schedule.exponential(\"1 second\"),\n until: (sessions) => sessions.length > 0,\n }),\n Effect.timeoutOption(orphanSearch),\n );\n\n if (Option.isNone(found) && !answered)\n return new Supervisor.Unconfirmed({\n detail: `Browserbase did not answer a search for it within ${Duration.format(orphanSearch)}`,\n });\n const running = Option.getOrElse(found, () => []).filter((session) => !ended(session));\n\n return yield* endAll(\n client,\n running.map((session) => session.id),\n settle,\n );\n });\n\n/**\n * Hold the stored context through the lease, as its only writer, until the scope closes or the\n * session's end is known; the hold goes once, saying how this writer leaves the context.\n */\nconst holdContext = Effect.fnUntraced(function* (\n client: Service,\n lease: ContextLease[\"Service\"],\n id: string,\n settle: Duration.Duration,\n) {\n const scope = yield* Scope.fork(yield* Effect.scope);\n\n // A second writer waits here for the first one's whole session and the save after it.\n const hold = yield* lease\n .hold(id)\n .pipe(\n Scope.provide(scope),\n Effect.withSpan(\"Browserbase.holdContext\", {}, { captureStackTrace: false }),\n );\n\n // Whether a session that saves to the context may run, as this writer would leave it now.\n let unsettled = hold.unsettled;\n\n const set = (now: boolean) =>\n Effect.sync(() => {\n unsettled = now;\n });\n\n yield* Scope.addFinalizer(\n scope,\n Effect.suspend(() => hold.leave(unsettled)),\n );\n\n const letGo = (now: boolean) => set(now).pipe(Effect.andThen(Scope.close(scope, Exit.void)));\n\n /** End the context's sessions but `except`, found by the label `open` gives them. */\n const end = (except: ReadonlyArray<string>) =>\n unended(client, labelled(contextLabel, id)).pipe(\n Effect.flatMap((found) =>\n endAll(\n client,\n found.map((session) => session.id).filter((session) => !except.includes(session)),\n settle,\n ),\n ),\n Effect.onExit((exit) => set(!(Exit.isSuccess(exit) && exit.value._tag === \"Settled\"))),\n );\n\n const refuse = (outcome: Supervisor.Released) =>\n outcome._tag === \"Settled\"\n ? Effect.void\n : Effect.fail(new ContextHeld({ context: id, detail: outcome.detail }));\n\n return {\n end,\n /**\n * End the sessions, but `except`, that a writer before may have left saving to the context,\n * failing with `ContextHeld` while they can't be confirmed ended.\n */\n clear: (except: ReadonlyArray<string>) =>\n Effect.suspend(() => (unsettled ? Effect.flatMap(end(except), refuse) : Effect.void)),\n /** A session that saves to the context runs from now. */\n writing: set(true),\n /** How the writer's session ended: unconfirmed, it may still save to the context. */\n released: (outcome: Supervisor.Released) => letGo(outcome._tag === \"Unconfirmed\"),\n /** How ending the session a lost create may have made went: unconfirmed, the open fails. */\n lost: (outcome: Supervisor.Released) =>\n letGo(outcome._tag === \"Unconfirmed\").pipe(Effect.andThen(refuse(outcome))),\n /** The writer's session runs on past its scope, saving to the context when it ends. */\n kept: letGo(true),\n };\n});\n\n/** A create that failed so may still have made its session: its answer is lost or unreadable. */\nconst mayHaveCreated = (error: BrowserbaseError) =>\n error.reason._tag === \"Transport\" ||\n error.reason._tag === \"Decode\" ||\n (error.reason._tag === \"Status\" && (error.reason.status >= 500 || error.reason.status === 408));\n\n/** A create's own nonce: two random draws, which no other create draws in practice. */\nconst nonce = Effect.map(Effect.all([Random.nextInt, Random.nextInt]), (draws) =>\n draws.map((draw) => Math.abs(draw).toString(36)).join(\"-\"),\n);\n\n/**\n * The create request, labelled with its own nonce, a persisting session with its context too, so\n * either can be found, and a kept one with what it is kept under, kept alive past disconnecting.\n */\nconst withLabels = (\n session: SessionOptions | undefined,\n own: string,\n context: string | undefined,\n keep: string | undefined,\n) => ({\n ...session,\n ...(keep === undefined ? {} : { keepAlive: true }),\n userMetadata: {\n ...session?.userMetadata,\n [createLabel]: own,\n ...(context === undefined ? {} : { [contextLabel]: context }),\n ...(keep === undefined ? {} : { [keepLabel]: keep }),\n },\n});\n\n/**\n * A release by the browser's owner: it closes the browser first, so that whatever fails then, a\n * capture's reader or a call in flight, says the session was released, and not that the\n * connection Browserbase cuts as the session ends was lost.\n */\nconst releasing = (browser: Scope.Closeable, end: Effect.Effect<Supervisor.Released>) =>\n Scope.close(browser, Exit.void).pipe(Effect.andThen(end));\n\n/**\n * A browser over the session's DevTools address, its pages' screencasts on a capture connection of\n * their own. A DevTools server's HTTP address, as a local Chromium gives in tests, keeps them on\n * each page's own session: there the connection is loopback, and fast. A session that has ended\n * fails `Closed` by the session, with no connect.\n */\nconst connect = Effect.fnUntraced(function* (\n operation: string,\n session: Session,\n options: Options,\n) {\n const endpoint = session.connectUrl;\n\n if (ended(session))\n return yield* new BrowserError({\n operation,\n reason: new Closed({ cause: \"session\" }),\n dispatched: false,\n });\n if (endpoint === undefined)\n return yield* new BrowserbaseError({\n operation,\n reason: new Decode({ detail: `session ${session.id} has no connectUrl` }),\n });\n const apart = options.captureConnection !== false && /^wss?:/i.test(Redacted.value(endpoint));\n\n return yield* Cdp.open({\n ...options,\n endpoint,\n id: session.id,\n provider: \"browserbase\",\n expiresAt: Option.getOrUndefined(DateTime.make(session.expiresAt)),\n capture: apart ? yield* CaptureConnection.make(endpoint) : undefined,\n });\n});\n\n/** How a supervisor keeps its sessions past its scope: under `name`, adopting one first if `adopt`. */\ninterface Keeping {\n readonly name: string;\n readonly adopt: boolean;\n}\n\nconst keepName = /^[\\w.:-]{1,64}$/;\n\nconst newestFirst = (sessions: ReadonlyArray<Session>) => {\n const created = (session: Session) =>\n Option.getOrElse(Option.map(DateTime.make(session.createdAt), DateTime.toEpochMillis), () => 0);\n\n return sessions.toSorted((a, b) => created(b) - created(a));\n};\n\n/**\n * The newest session kept under `name` that saves where this open would, to adopt. Every other\n * session kept under it is to end, since nothing else adopts it: those that save to this open's\n * context are its writers, for the context's hold to end, as `writers` says, and the rest end here.\n */\nconst adoptable = Effect.fnUntraced(function* (\n client: Service,\n name: string,\n persisting: string | undefined,\n) {\n const [newest, ...older] = newestFirst(yield* unended(client, labelled(keepLabel, name)));\n const fits = newest !== undefined && newest.userMetadata?.[contextLabel] === persisting;\n const others = [...(fits || newest === undefined ? [] : [newest]), ...older];\n\n const writes = (session: Session) =>\n persisting !== undefined && session.userMetadata?.[contextLabel] === persisting;\n\n const rest = others.filter((session) => !writes(session));\n\n if (rest.length > 0) {\n const outcome = yield* endAll(\n client,\n rest.map((session) => session.id),\n undefined,\n );\n\n yield* Effect.annotateCurrentSpan({ endedKept: rest.length, endedKeptAs: outcome._tag });\n }\n\n return { adoptee: fits ? newest : undefined, writers: others.some(writes) };\n});\n\n/**\n * Open a browser on a new session, or, when keeping, adopt one a supervisor kept before. A kept\n * session's scope only disconnects, unless it closes on a failure: `release` ends it.\n */\nconst start = Effect.fnUntraced(function* (options: Options, keeping: Keeping | undefined) {\n const client = yield* BrowserbaseClient;\n const lease = yield* ContextLease;\n const context = options.session?.browserSettings?.context;\n const persisting = context?.persist === true ? context.id : undefined;\n const local = yield* Scope.fork(yield* Effect.scope);\n const settle = Duration.fromInputUnsafe(options.contextSettle ?? Duration.seconds(10));\n\n return yield* Effect.gen(function* () {\n if (keeping !== undefined && !keepName.test(keeping.name))\n return yield* new BrowserbaseError({\n operation: \"supervise\",\n reason: new InvalidRequest({\n detail: `keep must be 1 to 64 letters, digits, \"_\", \".\", \":\" or \"-\"`,\n }),\n });\n\n const writing =\n persisting === undefined ? undefined : yield* holdContext(client, lease, persisting, settle);\n\n const adoption = keeping?.adopt\n ? yield* adoptable(client, keeping.name, persisting)\n : undefined;\n\n const adopted = adoption?.adoptee;\n\n // Another writer kept under the name may still save to the context: clear it as any other.\n if (adoption?.writers === true) yield* writing?.writing ?? Effect.void;\n yield* writing?.clear(adopted === undefined ? [] : [adopted.id]) ?? Effect.void;\n const connected = yield* Scope.fork(local);\n const own = yield* nonce;\n\n // Releasing ends the session; leaving, as a kept session's scope does, only disconnects.\n const ending = (session: Session) =>\n Effect.gen(function* () {\n let asked = false;\n\n const release = yield* Effect.cached(\n Effect.suspend(() => {\n asked = true;\n\n return releasing(connected, confirm(client, session.id, writing && settle)).pipe(\n Effect.tap((outcome) => writing?.released(outcome) ?? Effect.void),\n );\n }),\n );\n\n const leave = Effect.suspend(() =>\n asked\n ? Effect.void\n : Scope.close(connected, Exit.void).pipe(Effect.andThen(writing?.kept ?? Effect.void)),\n );\n\n return { session, release, leave };\n });\n\n const made = yield* Effect.acquireRelease(\n Effect.gen(function* () {\n const session =\n adopted === undefined\n ? yield* client.createSession(\n withLabels(options.session, own, persisting, keeping?.name),\n )\n : yield* client.getSession(adopted.id);\n\n yield* writing?.writing ?? Effect.void;\n\n return yield* ending(session);\n }),\n ({ release, leave }, exit) =>\n keeping !== undefined && Exit.isSuccess(exit) ? leave : Effect.asVoid(release),\n ).pipe(\n // A session nobody can see bills until its timeout, and one that saves to the context would\n // write beside the next writer: end it, found by its create's own label.\n Effect.tapError((error) =>\n adopted === undefined && mayHaveCreated(error)\n ? endOrphan(client, own, writing && settle).pipe(\n Effect.flatMap((outcome) => writing?.lost(outcome) ?? Effect.void),\n )\n : Effect.void,\n ),\n );\n\n const { session, release } = made;\n\n yield* Effect.annotateCurrentSpan({\n session: session.id,\n region: session.region,\n adopted: adopted !== undefined,\n });\n\n const browser = yield* connect(\n adopted === undefined ? \"open\" : \"attach\",\n session,\n options,\n ).pipe(Scope.provide(connected));\n\n return { browser, session, release } satisfies Hosted;\n }).pipe(\n Scope.provide(local),\n Effect.onError((cause) => Scope.close(local, Exit.failCause(cause))),\n );\n});\n\n/**\n * Create a session and open a `Browser` on it, for as long as the scope is open. If opening\n * fails, the session and context are released then, so a retry in the same scope can take them.\n * A persisting open holds its context through the `ContextLease`; a session that may still save\n * to it, as one whose release was left `Unconfirmed` or whose create's answer was lost, is ended\n * first, and the open fails with `ContextHeld` while that can't be confirmed. A lost create's own\n * open looks for its session by the create's nonce, within `orphanSearch`, ends it, then fails with\n * the create's error. `release` disconnects the browser before it asks Browserbase to end the\n * session, so what fails meanwhile says it was released.\n */\nexport const open = Effect.fn(\"Browserbase.open\")(function* (options: Options = {}) {\n return yield* start(options, undefined);\n});\n\n/**\n * Open a `Browser` on a session that already runs, such as a `keepAlive` session another process\n * opened. This is resume: its pages keep their ids, their CDP target ids, so `browser.page(id)`\n * finds a page stored before. Closing the scope disconnects and leaves the session running;\n * `release` ends it. A session that has ended fails `Closed` by the session. It holds no context.\n */\nexport const attach = Effect.fn(\"Browserbase.attach\")(function* (\n sessionId: string,\n options: Options = {},\n) {\n const client = yield* BrowserbaseClient;\n const session = yield* client.getSession(sessionId);\n\n yield* Effect.annotateCurrentSpan({ session: session.id, region: session.region });\n\n const connected = yield* Scope.fork(yield* Effect.scope);\n const browser = yield* connect(\"attach\", session, options).pipe(Scope.provide(connected));\n\n const release = yield* Effect.cached(\n releasing(connected, confirm(client, session.id, undefined)),\n );\n\n return { browser, session, release } satisfies Hosted;\n});\n\n/**\n * End a stored context's sessions, the ones `open` labelled as writing to it, and let the context\n * go once they are confirmed ended and its save has settled. `open` does this itself when a writer\n * before it may still run; `reconcile` does it without opening, as for sessions another process\n * left running. It holds the context through the `ContextLease`, so it waits for a writer. A\n * session still running at the deadline makes it `Unconfirmed`, and leaves the context unsettled,\n * as a failure does.\n */\nexport const reconcile = Effect.fn(\"Browserbase.reconcile\")(function* (\n contextId: string,\n options: { readonly contextSettle?: Duration.Input | undefined } = {},\n) {\n const client = yield* BrowserbaseClient;\n const lease = yield* ContextLease;\n const settle = Duration.fromInputUnsafe(options.contextSettle ?? Duration.seconds(10));\n\n // Reading the context first refuses an id that is not one before it reaches the query.\n yield* client.getContext(contextId);\n const hold = yield* holdContext(client, lease, contextId, settle);\n\n return yield* hold.end([]);\n}, Effect.scoped);\n\n/**\n * Read a stored context back, as a login: a session that loads it and saves nothing runs `check`\n * on its browser, and is released. The context is held through the `ContextLease` meanwhile, so\n * the read never runs beside a writer, which a site could sign out, and it reads what the last\n * writer saved, once that save settled. A session a writer before may have left saving to it is\n * ended first, as for `open`.\n */\nexport const verifyContext = Effect.fn(\"Browserbase.verifyContext\")(function* <A, E, R>(\n contextId: string,\n check: (browser: Browser.Service) => Effect.Effect<A, E, R>,\n options: Options = {},\n) {\n const client = yield* BrowserbaseClient;\n const lease = yield* ContextLease;\n const settle = Duration.fromInputUnsafe(options.contextSettle ?? Duration.seconds(10));\n const reading = yield* holdContext(client, lease, contextId, settle);\n\n yield* reading.clear([]);\n\n const { browser } = yield* start(\n {\n ...options,\n session: {\n ...options.session,\n browserSettings: {\n ...options.session?.browserSettings,\n context: { id: contextId, persist: false },\n },\n },\n },\n undefined,\n );\n\n return yield* check(browser);\n}, Effect.scoped);\n\nexport interface SuperviseOptions<A = Session, E = never, R = never>\n extends\n Options,\n Pick<\n Supervisor.Options<\n BrowserError | BrowserbaseError | ContextHeld | E,\n BrowserbaseClient | ContextLease | R,\n A\n >,\n \"reopen\" | \"rotateBefore\" | \"waitTimeout\" | \"handover\"\n > {\n /**\n * Keep the session past the supervisor's scope, under this name: 1 to 64 letters, digits, `_`,\n * `.`, `:` or `-`. Each session is created with `keepAlive` and labelled `keptAs: <keep>` in its\n * user metadata. Closing the scope only disconnects the current one, published as `Kept`, and\n * the first generation of the next `supervise` under the same name adopts it, with its pages,\n * rather than creating a session; other sessions kept under it are ended. `retire` releases. A\n * kept session bills until it is adopted and released, or until its timeout ends it.\n */\n readonly keep?: string | undefined;\n /** Build the generation's value in its scope. Without a builder, its value is its Session. */\n readonly build?: ((hosted: Hosted) => Effect.Effect<A, E, R>) | undefined;\n}\n\n/**\n * Browserbase refused the request: no new try mends a refused key, request or id. A context held\n * is not among them, since each try ends its sessions again.\n */\nconst refused = (error: unknown) =>\n Schema.is(BrowserbaseError)(error) && !isTransient(error) && error.reason._tag !== \"Decode\";\n\n/**\n * Keep Browserbase sessions open as `Supervisor` generations, each a new session made from\n * `session`. Sessions that persist to a stored context are exclusive: a rotation releases the\n * current one, and its context's save settles, before the next one opens. An open Browserbase\n * refused, as for a bad key or an invalid request, is `Down` at once. With `keep`, closing the\n * scope leaves the current session running for the next `supervise` under that name to adopt.\n */\nexport function supervise<A, E, R>(\n options: SuperviseOptions<A, E, R> & {\n readonly build: (hosted: Hosted) => Effect.Effect<A, E, R>;\n },\n): Effect.Effect<\n Supervisor.Supervisor<A>,\n never,\n Scope.Scope | BrowserbaseClient | ContextLease | Exclude<R, Scope.Scope>\n>;\n\nexport function supervise<A = Session, E = never, R = never>(\n options?: SuperviseOptions<A, E, R>,\n): Effect.Effect<\n Supervisor.Supervisor<A | Session>,\n never,\n Scope.Scope | BrowserbaseClient | ContextLease | Exclude<R, Scope.Scope>\n>;\n\nexport function supervise<A = Session, E = never, R = never>(\n options: SuperviseOptions<A, E, R> = {},\n) {\n return Effect.suspend(() => {\n const { keep } = options;\n // Only the first generation adopts a kept session: a later one would find its own.\n let opened = false;\n\n return Supervisor.make({\n open: Effect.gen(function* () {\n const hosted = yield* start(\n options,\n keep === undefined ? undefined : { name: keep, adopt: !opened },\n );\n\n opened = true;\n // The generation owns resources acquired by build, including on failure or cancellation.\n const value = options.build === undefined ? hosted.session : yield* options.build(hosted);\n\n return { ...hosted, value };\n }).pipe(Effect.withSpan(\"Browserbase.open\", {}, { captureStackTrace: false })),\n exclusive: options.session?.browserSettings?.context?.persist === true,\n keep: keep !== undefined,\n reopen: options.reopen,\n definite: refused,\n rotateBefore: options.rotateBefore,\n waitTimeout: options.waitTimeout,\n handover: options.handover,\n });\n });\n}\n\nexport const layer = (\n options: Options = {},\n): Layer.Layer<\n Browser.Browser,\n BrowserError | BrowserbaseError | ContextHeld,\n BrowserbaseClient | ContextLease\n> =>\n Layer.effect(\n Browser.Browser,\n Effect.map(open(options), ({ browser }) => browser),\n );\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAgBA,MAAM,UAAU,OAAO,eACrB,OAAO,OAAO;CACZ,IAAI,OAAO,YAAY,OAAO,GAAG;CACjC,WAAW,OAAO,YAAY,OAAO,MAAM;CAC3C,QAAQ,OAAO,YAAY,OAAO,MAAM;CACxC,QAAQ,OAAO,YAAY,OAAO,OAAO;CACzC,QAAQ,OAAO,YAAY,OAAO,OAAO;CACzC,OAAO,OAAO,YAAY,OAAO,OAAO,EAAE,SAAS,OAAO,OAAO,CAAC,CAAC;AACrE,CAAC,CACH;AAEA,MAAM,UAAU,OAAO,OAAO,EAAE,WAAW,OAAO,OAAO,CAAC;AAoB1D,MAAM,WAAW,WACf,IAAI,aAAa;CAAE,WAAW;CAAc,QAAQ,IAAI,OAAO,EAAE,OAAO,CAAC;CAAG,YAAY;AAAM,CAAC;AAEjG,MAAM,UAAU,SAAS,QAAQ,CAAC;;AAGlC,MAAa,OAAO,OAAO,WAAW,WAAW,KAAgC;CAC/E,IAAI,QAAe,EAAE,MAAM,OAAO;CAClC,IAAI,MAAM;CACV,MAAM,UAAU,OAAO,UAAU,KAAK,CAAC;CAGvC,MAAM,QAAQ,MAAY,UAAwB;EAChD,IAAI,MAAM,SAAS,UAAU,MAAM,SAAS,MAAM;EAClD,QAAQ,EAAE,MAAM,OAAO;EACvB,KAAK,MAAM,SAAS,KAAK,QAAQ,OAAO,GAAG,MAAM,OAAO,KAAK;EAC7D,KAAK,MAAM,YAAY,KAAK,SAAS,OAAO,GAAG,SAAS,KAAK,KAAK;EAClE,KAAK,QAAQ,MAAM;EACnB,KAAK,SAAS,MAAM;CACtB;CAEA,MAAM,WAAW,MAAY,SAAkB;EAC7C,MAAM,UAAU,OAAO,SAAS,WAAW,OAAO,aAAa,OAAO,CAAC,CAAC,IAAI,IAAI,OAAO,KAAK;EAE5F,IAAI,OAAO,OAAO,OAAO,GACvB,OAAO,KAAK,MAAM,QAAQ,yDAAyD,CAAC;EACtF,MAAM,EAAE,IAAI,WAAW,QAAQ,QAAQ,QAAQ,UAAU,QAAQ;EAEjE,IAAI,OAAO,KAAA,GAAW;GACpB,MAAM,QAAQ,KAAK,QAAQ,IAAI,EAAE;GAEjC,KAAK,QAAQ,OAAO,EAAE;GACtB,IAAI,UAAU,KAAA,GAAW,OAAO,QAAQ,MAAM;QACzC,OAAO,OAAO,QAAQ,MAAM,OAAO,CAAC;EAC3C,OAAO,IAAI,WAAW,KAAA,GAAW;OAC5B,IAAI,cAAc,KAAA,GAAW,KAAK,SAAS,IAAI,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM;OAE/E,IAAI,WAAW,6BAA6B;GAC/C,MAAM,WAAW,OAAO,oBAAoB,OAAO,CAAC,CAAC,MAAM;GAC3D,MAAM,QAAQ,OAAO,OAAO,QAAQ,IAAI,SAAS,MAAM,YAAY;GACnE,MAAM,WAAW,KAAK,SAAS,IAAI,KAAK;GAExC,KAAK,SAAS,OAAO,KAAK;GAC1B,UAAU,MAAM,QAAQ,MAAM;EAChC;CACF;CAEA,MAAM,QACJ,MACA,QACA,QACA,cACG;EACH,IAAI,MAAM,SAAS,UAAU,MAAM,SAAS,MAC1C,OAAO,QAAQ,OAAO,QAAQ,iCAAiC,CAAC;EAClE,MAAM,KAAK,EAAE;EACb,MAAM,EAAE,SAAS,SAAS,WAAW,QAAQ,cAAuB;EAEpE,KAAK,QAAQ,IAAI,IAAI;GAAE;GAAS;EAAO,CAAC;EACxC,IAAI;GACF,KAAK,OAAO,KAAK,KAAK,UAAU;IAAE;IAAI;IAAQ;IAAQ;GAAU,CAAC,CAAC;EACpE,QAAQ;GACN,KAAK,QAAQ,OAAO,EAAE;GACtB,OAAO,QAAQ,uCAAuC,CAAC;EACzD;EAEA,OAAO;CACT;CAEA,MAAM,UAAU,OAAO,UAA8B,WAAW;EAC9D,MAAM,SAAS,IAAI,UAAU,SAAS,MAAM,GAAG,CAAC;EAChD,MAAM,OAAa;GAAE;GAAQ,yBAAS,IAAI,IAAI;GAAG,0BAAU,IAAI,IAAI;EAAE;EAErE,MAAM,iBAAiB,OAAO,OAAO,KAAK,QAAQ,qCAAqC,CAAC,CAAC;EAEzF,OAAO,iBAAiB,SAAS,UAAU,EAAE,MAAM,KAAK,CAAC;EACzD,OAAO,iBACL,cACM;GACJ,OAAO,oBAAoB,SAAS,QAAQ;GAE5C,IAAI,MAAM,SAAS,UAAU;IAC3B,OAAO,MAAM,GAAI;IAEjB,OAAO,OAAO,OAAO,KAAK,QAAQ,kCAAkC,CAAC,CAAC;GACxE;GACA,QAAQ;IAAE,MAAM;IAAQ;GAAK;GAC7B,OAAO,iBAAiB,eACtB,KAAK,MAAM,QAAQ,iCAAiC,CAAC,CACvD;GACA,OAAO,OAAO,QAAQ,IAAI,CAAC;EAC7B,GACA,EAAE,MAAM,KAAK,CACf;EACA,OAAO,iBAAiB,YAAY,EAAE,WAAkC,QAAQ,MAAM,IAAI,CAAC;EAE3F,OAAO,OAAO,WAAW,OAAO,MAAM,GAAI,CAAC;CAC7C,CAAC;CAED,MAAM,UAAU,QAAQ,YAAY,CAAC,CAAC,CACpC,OAAO,cACL,MAAM,SAAS,SACX,OAAO,QAAQ,MAAM,IAAI,IACzB,MAAM,SAAS,WACb,OAAO,KAAK,QAAQ,kCAAkC,CAAC,IACvD,OACR,CACF;CAEA,MAAM,WAAW,UACf,OAAO,WAAW;EAChB,KAAK;EACL,QAAQ,UACN,OAAO,GAAG,YAAY,CAAC,CAAC,KAAK,IAAI,QAAQ,QAAQ,+BAA+B;CACpF,CAAC;CAEH,MAAM,UAAmC,QAAQ,aAC/C,OAAO,IAAI,aAAa;EACtB,MAAM,OAAO,OAAO;EAEpB,MAAM,EAAE,cAAc,OAAO,cAC3B,KAAK,MAAM,yBAAyB;GAAE,UAAU;GAAQ,SAAS;EAAK,CAAC,CACzE,CAAC,CAAC,KACA,OAAO,SAAS,WACd,OAAO,oBAAoB,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,KAC1C,OAAO,eAAe,QAAQ,gDAAgD,CAAC,CACjF,CACF,CACF;EAEA,KAAK,SAAS,IAAI,WAAW,QAAQ;EAErC,OAAO,OAAO,mBACZ,OAAO,WAAW;GAChB,IAAI,KAAK,SAAS,OAAO,SAAS,GAChC,KAAU,MAAM,2BAA2B,EAAE,UAAU,GAAG,KAAA,CAAS,CAAC,CAAC,YAC7D,KAAA,CACR;EACJ,CAAC,CACH;EAEA,QAAQ,QAAQ,WAAW,KAAK,MAAM,QAAQ,QAAQ,SAAS;CACjE,CAAC;CAGH,OAAO,OAAO,mBACZ,OAAO,cAAc;EACnB,MAAM,WAAW;EAEjB,QAAQ,EAAE,MAAM,SAAS;EACzB,IAAI,SAAS,SAAS,QAAQ,OAAO,OAAO;EAC5C,MAAM,EAAE,QAAQ,SAAS,aAAa,SAAS;EAE/C,KAAK,MAAM,SAAS,QAAQ,OAAO,GAAG,MAAM,OAAO,QAAQ,+BAA+B,CAAC;EAC3F,QAAQ,MAAM;EACd,SAAS,MAAM;EAEf,OAAO,OAAO,UAAgB,WAAW;GACvC,IAAI,OAAO,eAAe,UAAU,QAAQ,OAAO,OAAO,OAAO,IAAI;GACrE,OAAO,iBAAiB,eAAe,OAAO,OAAO,IAAI,GAAG,EAAE,MAAM,KAAK,CAAC;GAC1E,OAAO,MAAM,GAAI;EACnB,CAAC,CAAC,CAAC,KAAK,OAAO,cAAc;GAAE,UAAU;GAAS,cAAc,OAAO;EAAK,CAAC,CAAC;CAChF,CAAC,CACH;CAEA,OAAO,EAAE,OAAO;AAClB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/HD,MAAM,eAAe;;AAGrB,MAAM,cAAc;;AAGpB,MAAM,YAAY;;;;;AAMlB,MAAM,eAAe,SAAS,QAAQ,EAAE;;AAGxC,MAAM,kBAAkB,SAAS,QAAQ,CAAC;AAE1C,MAAM,SAAS,YAAqB,QAAQ,WAAW,aAAa,QAAQ,WAAW;;;;;;;AAQvF,MAAM,WAAW,QAAiB,IAAY,WAC5C,OAAO,IAAI,aAAa;CAEtB,IAAI,OAAO;CAEX,MAAM,SAAS,UAA4B,OAAO,WAAY,OAAO,MAAM,OAAQ;CAEnF,MAAM,OAAO,OAAO,WAAW,EAAE,CAAC,CAAC,KACjC,OAAO,SAAS,KAAK,GACrB,OAAO,KAAK,YAAY,OAAO,WAAY,OAAO,mBAAmB,QAAQ,QAAS,CAAC,GACvF,OAAO,MAAM,SAAS,OAAO,UAAU,CAAC,GACxC,OAAO,OAAO;EAAE,OAAO;EAAO,UAAU,SAAS,OAAO,UAAU;CAAE,CAAC,CACvE;CAcA,IAAI,EAAC,OAXoB,OAAO,eAAe,EAAE,CAAC,CAAC,KACjD,OAAO,SAAS,KAAK,GACrB,OAAO,MAAM;EAAE,OAAO;EAAa,UAAU,SAAS,OAAO,UAAU;CAAE,CAAC,GAC1E,OAAO,MACP,OAAO,QAAQ,IAAI,GACnB,OAAO,GAAG,IAAI,GACd,OAAO,cAAc;EAAE,UAAU;EAAiB,cAAc,OAAO,QAAQ,KAAK;CAAE,CAAC,GAEvF,OAAO,oBAAoB,KAAK,CAClC,IAGE,OAAO,IAAI,WAAW,YAAY,EAChC,QAAQ,GAAG,KAAK,GAAG,SAAS,OAAO,eAAe,EAAE,oBACtD,CAAC;CACH,IAAI,WAAW,KAAA,GAAW,OAAO,OAAO,MAAM,MAAM;CAEpD,OAAO,IAAI,WAAW,QAAQ;AAChC,CAAC,CAAC,CAAC,KACD,OAAO,KAAK,aAAa,OAAO,oBAAoB,EAAE,UAAU,SAAS,KAAK,CAAC,CAAC,GAChF,OAAO,SACL,uBACA,EAAE,YAAY;CAAE,SAAS;CAAI,QAAQ,WAAW,KAAA;AAAU,EAAE,GAC5D,EAAE,mBAAmB,MAAM,CAC7B,GACA,OAAO,eACT;;AAGF,MAAM,YAAY,OAAe,UAAkB,kBAAkB,MAAM,MAAM,MAAM;;;;;AAMvF,MAAM,WAAW,QAAiB,UAChC,OAAO,QAAQ,CAAC,WAAW,SAAS,IAAI,WAAW,OAAO,aAAa;CAAE;CAAQ;AAAM,CAAC,CAAC,CAAC,CAAC,KACzF,OAAO,KAAK,UAAU,CACpB,GAAG,IAAI,IAAI,MAAM,KAAK,CAAC,CAAC,KAAK,YAAY,CAAC,QAAQ,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAC1E,CAAC,CACH;;;;;AAMF,MAAM,UACJ,QACA,UACA,WAEA,OAAO,QAAQ,WAAW,YAAY,QAAQ,QAAQ,SAAS,KAAA,CAAS,GAAG,EACzE,aAAa,EACf,CAAC,CAAC,CAAC,KACD,OAAO,SAAS,aAAa;CAC3B,MAAM,cAAc,SAAS,MAAM,YAAY,QAAQ,SAAS,aAAa;CAE7E,OAAO,gBAAgB,KAAA,IACnB,OAAO,MAAM,UAAU,SAAS,IAAI,CAAC,CAAC,KACpC,OAAO,GAAwB,IAAI,WAAW,QAAQ,CAAC,CACzD,IACA,OAAO,QAA6B,WAAW;AACrD,CAAC,CACH;;;;;;;;AASF,MAAM,aAAa,QAAiB,OAAe,WACjD,OAAO,IAAI,aAAa;CACtB,IAAI,WAAW;CAEf,MAAM,QAAQ,OAAO,OAAO,aAAa,EAAE,OAAO,SAAS,aAAa,KAAK,EAAE,CAAC,CAAC,CAAC,KAChF,OAAO,UACL,OAAO,WAAW;EAChB,WAAW;CACb,CAAC,CACH,GACA,OAAO,MAAM,SAAS,YAAY,UAAU,CAAC,GAC7C,OAAO,OAAO;EACZ,UAAU,SAAS,YAAY,UAAU;EACzC,QAAQ,aAAa,SAAS,SAAS;CACzC,CAAC,GACD,OAAO,cAAc,YAAY,CACnC;CAEA,IAAI,OAAO,OAAO,KAAK,KAAK,CAAC,UAC3B,OAAO,IAAI,WAAW,YAAY,EAChC,QAAQ,qDAAqD,SAAS,OAAO,YAAY,IAC3F,CAAC;CACH,MAAM,UAAU,OAAO,UAAU,aAAa,CAAC,CAAC,CAAC,CAAC,QAAQ,YAAY,CAAC,MAAM,OAAO,CAAC;CAErF,OAAO,OAAO,OACZ,QACA,QAAQ,KAAK,YAAY,QAAQ,EAAE,GACnC,MACF;AACF,CAAC;;;;;AAMH,MAAM,cAAc,OAAO,WAAW,WACpC,QACA,OACA,IACA,QACA;CACA,MAAM,QAAQ,OAAO,MAAM,KAAK,OAAO,OAAO,KAAK;CAGnD,MAAM,OAAO,OAAO,MACjB,KAAK,EAAE,CAAC,CACR,KACC,MAAM,QAAQ,KAAK,GACnB,OAAO,SAAS,2BAA2B,CAAC,GAAG,EAAE,mBAAmB,MAAM,CAAC,CAC7E;CAGF,IAAI,YAAY,KAAK;CAErB,MAAM,OAAO,QACX,OAAO,WAAW;EAChB,YAAY;CACd,CAAC;CAEH,OAAO,MAAM,aACX,OACA,OAAO,cAAc,KAAK,MAAM,SAAS,CAAC,CAC5C;CAEA,MAAM,SAAS,QAAiB,IAAI,GAAG,CAAC,CAAC,KAAK,OAAO,QAAQ,MAAM,MAAM,OAAO,KAAK,IAAI,CAAC,CAAC;;CAG3F,MAAM,OAAO,WACX,QAAQ,QAAQ,SAAS,cAAc,EAAE,CAAC,CAAC,CAAC,KAC1C,OAAO,SAAS,UACd,OACE,QACA,MAAM,KAAK,YAAY,QAAQ,EAAE,CAAC,CAAC,QAAQ,YAAY,CAAC,OAAO,SAAS,OAAO,CAAC,GAChF,MACF,CACF,GACA,OAAO,QAAQ,SAAS,IAAI,EAAE,KAAK,UAAU,IAAI,KAAK,KAAK,MAAM,SAAS,UAAU,CAAC,CACvF;CAEF,MAAM,UAAU,YACd,QAAQ,SAAS,YACb,OAAO,OACP,OAAO,KAAK,IAAI,YAAY;EAAE,SAAS;EAAI,QAAQ,QAAQ;CAAO,CAAC,CAAC;CAE1E,OAAO;EACL;;;;;EAKA,QAAQ,WACN,OAAO,cAAe,YAAY,OAAO,QAAQ,IAAI,MAAM,GAAG,MAAM,IAAI,OAAO,IAAK;;EAEtF,SAAS,IAAI,IAAI;;EAEjB,WAAW,YAAiC,MAAM,QAAQ,SAAS,aAAa;;EAEhF,OAAO,YACL,MAAM,QAAQ,SAAS,aAAa,CAAC,CAAC,KAAK,OAAO,QAAQ,OAAO,OAAO,CAAC,CAAC;;EAE5E,MAAM,MAAM,IAAI;CAClB;AACF,CAAC;;AAGD,MAAM,kBAAkB,UACtB,MAAM,OAAO,SAAS,eACtB,MAAM,OAAO,SAAS,YACrB,MAAM,OAAO,SAAS,aAAa,MAAM,OAAO,UAAU,OAAO,MAAM,OAAO,WAAW;;AAG5F,MAAM,QAAQ,OAAO,IAAI,OAAO,IAAI,CAAC,OAAO,SAAS,OAAO,OAAO,CAAC,IAAI,UACtE,MAAM,KAAK,SAAS,KAAK,IAAI,IAAI,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAC3D;;;;;AAMA,MAAM,cACJ,SACA,KACA,SACA,UACI;CACJ,GAAG;CACH,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,WAAW,KAAK;CAChD,cAAc;EACZ,GAAG,SAAS;GACX,cAAc;EACf,GAAI,YAAY,KAAA,IAAY,CAAC,IAAI,GAAG,eAAe,QAAQ;EAC3D,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,GAAG,YAAY,KAAK;CACpD;AACF;;;;;;AAOA,MAAM,aAAa,SAA0B,QAC3C,MAAM,MAAM,SAAS,KAAK,IAAI,CAAC,CAAC,KAAK,OAAO,QAAQ,GAAG,CAAC;;;;;;;AAQ1D,MAAM,UAAU,OAAO,WAAW,WAChC,WACA,SACA,SACA;CACA,MAAM,WAAW,QAAQ;CAEzB,IAAI,MAAM,OAAO,GACf,OAAO,OAAO,IAAI,aAAa;EAC7B;EACA,QAAQ,IAAI,OAAO,EAAE,OAAO,UAAU,CAAC;EACvC,YAAY;CACd,CAAC;CACH,IAAI,aAAa,KAAA,GACf,OAAO,OAAO,IAAI,iBAAiB;EACjC;EACA,QAAQ,IAAI,OAAO,EAAE,QAAQ,WAAW,QAAQ,GAAG,oBAAoB,CAAC;CAC1E,CAAC;CACH,MAAM,QAAQ,QAAQ,sBAAsB,SAAS,UAAU,KAAK,SAAS,MAAM,QAAQ,CAAC;CAE5F,OAAO,OAAO,IAAI,KAAK;EACrB,GAAG;EACH;EACA,IAAI,QAAQ;EACZ,UAAU;EACV,WAAW,OAAO,eAAe,SAAS,KAAK,QAAQ,SAAS,CAAC;EACjE,SAAS,QAAQ,OAAOA,KAAuB,QAAQ,IAAI,KAAA;CAC7D,CAAC;AACH,CAAC;AAQD,MAAM,WAAW;AAEjB,MAAM,eAAe,aAAqC;CACxD,MAAM,WAAW,YACf,OAAO,UAAU,OAAO,IAAI,SAAS,KAAK,QAAQ,SAAS,GAAG,SAAS,aAAa,SAAS,CAAC;CAEhG,OAAO,SAAS,UAAU,GAAG,MAAM,QAAQ,CAAC,IAAI,QAAQ,CAAC,CAAC;AAC5D;;;;;;AAOA,MAAM,YAAY,OAAO,WAAW,WAClC,QACA,MACA,YACA;CACA,MAAM,CAAC,QAAQ,GAAG,SAAS,YAAY,OAAO,QAAQ,QAAQ,SAAS,WAAW,IAAI,CAAC,CAAC;CACxF,MAAM,OAAO,WAAW,KAAA,KAAa,OAAO,eAAe,kBAAkB;CAC7E,MAAM,SAAS,CAAC,GAAI,QAAQ,WAAW,KAAA,IAAY,CAAC,IAAI,CAAC,MAAM,GAAI,GAAG,KAAK;CAE3E,MAAM,UAAU,YACd,eAAe,KAAA,KAAa,QAAQ,eAAe,kBAAkB;CAEvE,MAAM,OAAO,OAAO,QAAQ,YAAY,CAAC,OAAO,OAAO,CAAC;CAExD,IAAI,KAAK,SAAS,GAAG;EACnB,MAAM,UAAU,OAAO,OACrB,QACA,KAAK,KAAK,YAAY,QAAQ,EAAE,GAChC,KAAA,CACF;EAEA,OAAO,OAAO,oBAAoB;GAAE,WAAW,KAAK;GAAQ,aAAa,QAAQ;EAAK,CAAC;CACzF;CAEA,OAAO;EAAE,SAAS,OAAO,SAAS,KAAA;EAAW,SAAS,OAAO,KAAK,MAAM;CAAE;AAC5E,CAAC;;;;;AAMD,MAAM,QAAQ,OAAO,WAAW,WAAW,SAAkB,SAA8B;CACzF,MAAM,SAAS,OAAO;CACtB,MAAM,QAAQ,OAAO;CACrB,MAAM,UAAU,QAAQ,SAAS,iBAAiB;CAClD,MAAM,aAAa,SAAS,YAAY,OAAO,QAAQ,KAAK,KAAA;CAC5D,MAAM,QAAQ,OAAO,MAAM,KAAK,OAAO,OAAO,KAAK;CACnD,MAAM,SAAS,SAAS,gBAAgB,QAAQ,iBAAiB,SAAS,QAAQ,EAAE,CAAC;CAErF,OAAO,OAAO,OAAO,IAAI,aAAa;EACpC,IAAI,YAAY,KAAA,KAAa,CAAC,SAAS,KAAK,QAAQ,IAAI,GACtD,OAAO,OAAO,IAAI,iBAAiB;GACjC,WAAW;GACX,QAAQ,IAAI,eAAe,EACzB,QAAQ,6DACV,CAAC;EACH,CAAC;EAEH,MAAM,UACJ,eAAe,KAAA,IAAY,KAAA,IAAY,OAAO,YAAY,QAAQ,OAAO,YAAY,MAAM;EAE7F,MAAM,WAAW,SAAS,QACtB,OAAO,UAAU,QAAQ,QAAQ,MAAM,UAAU,IACjD,KAAA;EAEJ,MAAM,UAAU,UAAU;EAG1B,IAAI,UAAU,YAAY,MAAM,OAAO,SAAS,WAAW,OAAO;EAClE,OAAO,SAAS,MAAM,YAAY,KAAA,IAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,OAAO;EAC3E,MAAM,YAAY,OAAO,MAAM,KAAK,KAAK;EACzC,MAAM,MAAM,OAAO;EAGnB,MAAM,UAAU,YACd,OAAO,IAAI,aAAa;GACtB,IAAI,QAAQ;GAkBZ,OAAO;IAAE;IAAS,SAAA,OAhBK,OAAO,OAC5B,OAAO,cAAc;KACnB,QAAQ;KAER,OAAO,UAAU,WAAW,QAAQ,QAAQ,QAAQ,IAAI,WAAW,MAAM,CAAC,CAAC,CAAC,KAC1E,OAAO,KAAK,YAAY,SAAS,SAAS,OAAO,KAAK,OAAO,IAAI,CACnE;IACF,CAAC,CACH;IAQ2B,OANb,OAAO,cACnB,QACI,OAAO,OACP,MAAM,MAAM,WAAW,KAAK,IAAI,CAAC,CAAC,KAAK,OAAO,QAAQ,SAAS,QAAQ,OAAO,IAAI,CAAC,CAG1D;GAAE;EACnC,CAAC;EA6BH,MAAM,EAAE,SAAS,YAAY,OA3BT,OAAO,eACzB,OAAO,IAAI,aAAa;GACtB,MAAM,UACJ,YAAY,KAAA,IACR,OAAO,OAAO,cACZ,WAAW,QAAQ,SAAS,KAAK,YAAY,SAAS,IAAI,CAC5D,IACA,OAAO,OAAO,WAAW,QAAQ,EAAE;GAEzC,OAAO,SAAS,WAAW,OAAO;GAElC,OAAO,OAAO,OAAO,OAAO;EAC9B,CAAC,IACA,EAAE,SAAS,SAAS,SACnB,YAAY,KAAA,KAAa,KAAK,UAAU,IAAI,IAAI,QAAQ,OAAO,OAAO,OAAO,CACjF,CAAC,CAAC,KAGA,OAAO,UAAU,UACf,YAAY,KAAA,KAAa,eAAe,KAAK,IACzC,UAAU,QAAQ,KAAK,WAAW,MAAM,CAAC,CAAC,KACxC,OAAO,SAAS,YAAY,SAAS,KAAK,OAAO,KAAK,OAAO,IAAI,CACnE,IACA,OAAO,IACb,CACF;EAIA,OAAO,OAAO,oBAAoB;GAChC,SAAS,QAAQ;GACjB,QAAQ,QAAQ;GAChB,SAAS,YAAY,KAAA;EACvB,CAAC;EAQD,OAAO;GAAE,SAAA,OANc,QACrB,YAAY,KAAA,IAAY,SAAS,UACjC,SACA,OACF,CAAC,CAAC,KAAK,MAAM,QAAQ,SAAS,CAAC;GAEb;GAAS;EAAQ;CACrC,CAAC,CAAC,CAAC,KACD,MAAM,QAAQ,KAAK,GACnB,OAAO,SAAS,UAAU,MAAM,MAAM,OAAO,KAAK,UAAU,KAAK,CAAC,CAAC,CACrE;AACF,CAAC;;;;;;;;;;;AAYD,MAAa,OAAO,OAAO,GAAG,kBAAkB,CAAC,CAAC,WAAW,UAAmB,CAAC,GAAG;CAClF,OAAO,OAAO,MAAM,SAAS,KAAA,CAAS;AACxC,CAAC;;;;;;;AAQD,MAAa,SAAS,OAAO,GAAG,oBAAoB,CAAC,CAAC,WACpD,WACA,UAAmB,CAAC,GACpB;CACA,MAAM,SAAS,OAAO;CACtB,MAAM,UAAU,OAAO,OAAO,WAAW,SAAS;CAElD,OAAO,OAAO,oBAAoB;EAAE,SAAS,QAAQ;EAAI,QAAQ,QAAQ;CAAO,CAAC;CAEjF,MAAM,YAAY,OAAO,MAAM,KAAK,OAAO,OAAO,KAAK;CAOvD,OAAO;EAAE,SAAA,OANc,QAAQ,UAAU,SAAS,OAAO,CAAC,CAAC,KAAK,MAAM,QAAQ,SAAS,CAAC;EAMtE;EAAS,SAAA,OAJJ,OAAO,OAC5B,UAAU,WAAW,QAAQ,QAAQ,QAAQ,IAAI,KAAA,CAAS,CAAC,CAC7D;CAEmC;AACrC,CAAC;;;;;;;;;AAUD,MAAa,YAAY,OAAO,GAAG,uBAAuB,CAAC,CAAC,WAC1D,WACA,UAAmE,CAAC,GACpE;CACA,MAAM,SAAS,OAAO;CACtB,MAAM,QAAQ,OAAO;CACrB,MAAM,SAAS,SAAS,gBAAgB,QAAQ,iBAAiB,SAAS,QAAQ,EAAE,CAAC;CAGrF,OAAO,OAAO,WAAW,SAAS;CAGlC,OAAO,QAAO,OAFM,YAAY,QAAQ,OAAO,WAAW,MAAM,EAAA,CAE7C,IAAI,CAAC,CAAC;AAC3B,GAAG,OAAO,MAAM;;;;;;;;AAShB,MAAa,gBAAgB,OAAO,GAAG,2BAA2B,CAAC,CAAC,WAClE,WACA,OACA,UAAmB,CAAC,GACpB;CACA,MAAM,SAAS,OAAO;CACtB,MAAM,QAAQ,OAAO;CACrB,MAAM,SAAS,SAAS,gBAAgB,QAAQ,iBAAiB,SAAS,QAAQ,EAAE,CAAC;CAGrF,QAAO,OAFgB,YAAY,QAAQ,OAAO,WAAW,MAAM,EAAA,CAEpD,MAAM,CAAC,CAAC;CAEvB,MAAM,EAAE,YAAY,OAAO,MACzB;EACE,GAAG;EACH,SAAS;GACP,GAAG,QAAQ;GACX,iBAAiB;IACf,GAAG,QAAQ,SAAS;IACpB,SAAS;KAAE,IAAI;KAAW,SAAS;IAAM;GAC3C;EACF;CACF,GACA,KAAA,CACF;CAEA,OAAO,OAAO,MAAM,OAAO;AAC7B,GAAG,OAAO,MAAM;;;;;AA8BhB,MAAM,WAAW,UACf,OAAO,GAAG,gBAAgB,CAAC,CAAC,KAAK,KAAK,CAAC,YAAY,KAAK,KAAK,MAAM,OAAO,SAAS;AA2BrF,SAAgB,UACd,UAAqC,CAAC,GACtC;CACA,OAAO,OAAO,cAAc;EAC1B,MAAM,EAAE,SAAS;EAEjB,IAAI,SAAS;EAEb,OAAO,WAAW,KAAK;GACrB,MAAM,OAAO,IAAI,aAAa;IAC5B,MAAM,SAAS,OAAO,MACpB,SACA,SAAS,KAAA,IAAY,KAAA,IAAY;KAAE,MAAM;KAAM,OAAO,CAAC;IAAO,CAChE;IAEA,SAAS;IAET,MAAM,QAAQ,QAAQ,UAAU,KAAA,IAAY,OAAO,UAAU,OAAO,QAAQ,MAAM,MAAM;IAExF,OAAO;KAAE,GAAG;KAAQ;IAAM;GAC5B,CAAC,CAAC,CAAC,KAAK,OAAO,SAAS,oBAAoB,CAAC,GAAG,EAAE,mBAAmB,MAAM,CAAC,CAAC;GAC7E,WAAW,QAAQ,SAAS,iBAAiB,SAAS,YAAY;GAClE,MAAM,SAAS,KAAA;GACf,QAAQ,QAAQ;GAChB,UAAU;GACV,cAAc,QAAQ;GACtB,aAAa,QAAQ;GACrB,UAAU,QAAQ;EACpB,CAAC;CACH,CAAC;AACH;AAEA,MAAa,SACX,UAAmB,CAAC,MAMpB,MAAM,OACJ,QAAQ,SACR,OAAO,IAAI,KAAK,OAAO,IAAI,EAAE,cAAc,OAAO,CACpD"}