effect-browserbase 0.2.0-beta.8 → 0.3.0-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/README.md +250 -313
  2. package/dist/Browserbase-FDltiz36.mjs +542 -0
  3. package/dist/Browserbase-FDltiz36.mjs.map +1 -0
  4. package/dist/Browserbase.d.mts +105 -0
  5. package/dist/Browserbase.mjs +3 -0
  6. package/dist/BrowserbaseClient-CtAQ2rg4.d.mts +195 -0
  7. package/dist/BrowserbaseClient.d.mts +2 -0
  8. package/dist/BrowserbaseClient.mjs +190 -0
  9. package/dist/BrowserbaseClient.mjs.map +1 -0
  10. package/dist/BrowserbaseError-D1EOrLNc.d.mts +79 -0
  11. package/dist/BrowserbaseError.d.mts +2 -0
  12. package/dist/BrowserbaseError.mjs +101 -0
  13. package/dist/BrowserbaseError.mjs.map +1 -0
  14. package/dist/ContextLease.d.mts +42 -0
  15. package/dist/ContextLease.mjs +80 -0
  16. package/dist/ContextLease.mjs.map +1 -0
  17. package/dist/index.d.mts +5 -27
  18. package/dist/index.mjs +5 -26
  19. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  20. package/dist/testing/index.d.mts +134 -0
  21. package/dist/testing/index.mjs +382 -0
  22. package/dist/testing/index.mjs.map +1 -0
  23. package/package.json +51 -121
  24. package/src/Browserbase.ts +698 -0
  25. package/src/BrowserbaseClient.ts +559 -0
  26. package/src/BrowserbaseError.ts +108 -0
  27. package/src/ContextLease.ts +118 -0
  28. package/src/index.ts +7 -0
  29. package/src/internal/captureConnection.ts +214 -0
  30. package/src/testing/BrowserbaseContract.ts +170 -0
  31. package/src/testing/TestBrowserbase.ts +445 -0
  32. package/src/testing/index.ts +7 -0
  33. package/dist/Account.d.mts +0 -32
  34. package/dist/Account.mjs +0 -36
  35. package/dist/Account.mjs.map +0 -1
  36. package/dist/Acquisition-BOABu_qJ.mjs +0 -244
  37. package/dist/Acquisition-BOABu_qJ.mjs.map +0 -1
  38. package/dist/Agents-CPaTOH_g.d.mts +0 -156
  39. package/dist/Agents.d.mts +0 -3
  40. package/dist/Agents.mjs +0 -292
  41. package/dist/Agents.mjs.map +0 -1
  42. package/dist/Allocation.d.mts +0 -97
  43. package/dist/Allocation.mjs +0 -27
  44. package/dist/Allocation.mjs.map +0 -1
  45. package/dist/Authorization-Ll5f_XNM.mjs +0 -12
  46. package/dist/Authorization-Ll5f_XNM.mjs.map +0 -1
  47. package/dist/Browser-ByrWJ0ss.mjs +0 -274
  48. package/dist/Browser-ByrWJ0ss.mjs.map +0 -1
  49. package/dist/Browser.d.mts +0 -83
  50. package/dist/Browser.mjs +0 -3
  51. package/dist/BrowserBinding.d.mts +0 -13
  52. package/dist/BrowserBinding.mjs +0 -31
  53. package/dist/BrowserBinding.mjs.map +0 -1
  54. package/dist/Certificates-D4NQmyeA.d.mts +0 -34
  55. package/dist/Certificates.d.mts +0 -3
  56. package/dist/Certificates.mjs +0 -85
  57. package/dist/Certificates.mjs.map +0 -1
  58. package/dist/Cleanup-DMTDBir8.d.mts +0 -23
  59. package/dist/Cleanup.d.mts +0 -3
  60. package/dist/Cleanup.mjs +0 -43
  61. package/dist/Cleanup.mjs.map +0 -1
  62. package/dist/Client-BEC4Q8ZS.mjs +0 -564
  63. package/dist/Client-BEC4Q8ZS.mjs.map +0 -1
  64. package/dist/Client-B_f6bBLT.d.mts +0 -52
  65. package/dist/Client.d.mts +0 -3
  66. package/dist/Client.mjs +0 -2
  67. package/dist/Connection-sxyxtwlk.mjs +0 -56
  68. package/dist/Connection-sxyxtwlk.mjs.map +0 -1
  69. package/dist/ContextCoordination.d.mts +0 -29
  70. package/dist/ContextCoordination.mjs +0 -94
  71. package/dist/ContextCoordination.mjs.map +0 -1
  72. package/dist/ContextWriter-CiEma24z.mjs +0 -204
  73. package/dist/ContextWriter-CiEma24z.mjs.map +0 -1
  74. package/dist/Contexts-DqdL7cyX.d.mts +0 -31
  75. package/dist/Contexts.d.mts +0 -3
  76. package/dist/Contexts.mjs +0 -97
  77. package/dist/Contexts.mjs.map +0 -1
  78. package/dist/Deadline-CrViaogr.mjs +0 -13
  79. package/dist/Deadline-CrViaogr.mjs.map +0 -1
  80. package/dist/Downloads-CX52GOFJ.d.mts +0 -43
  81. package/dist/Downloads.d.mts +0 -3
  82. package/dist/Downloads.mjs +0 -137
  83. package/dist/Downloads.mjs.map +0 -1
  84. package/dist/Errors.d.mts +0 -100
  85. package/dist/Errors.mjs +0 -194
  86. package/dist/Errors.mjs.map +0 -1
  87. package/dist/Extensions-BTUn9zhK.mjs +0 -231
  88. package/dist/Extensions-BTUn9zhK.mjs.map +0 -1
  89. package/dist/Extensions-DBXuVM1f.d.mts +0 -43
  90. package/dist/Extensions.d.mts +0 -3
  91. package/dist/Extensions.mjs +0 -2
  92. package/dist/Functions-CsKMMUuZ.d.mts +0 -226
  93. package/dist/Functions.d.mts +0 -3
  94. package/dist/Functions.mjs +0 -318
  95. package/dist/Functions.mjs.map +0 -1
  96. package/dist/Issued-DejqoMYL.mjs +0 -15
  97. package/dist/Issued-DejqoMYL.mjs.map +0 -1
  98. package/dist/Launch-cAdE2rrZ.mjs +0 -115
  99. package/dist/Launch-cAdE2rrZ.mjs.map +0 -1
  100. package/dist/Launch.d.mts +0 -127
  101. package/dist/Launch.mjs +0 -97
  102. package/dist/Launch.mjs.map +0 -1
  103. package/dist/PageFetch-CjAM_0DS.d.mts +0 -40
  104. package/dist/PageFetch.d.mts +0 -3
  105. package/dist/PageFetch.mjs +0 -59
  106. package/dist/PageFetch.mjs.map +0 -1
  107. package/dist/Projects-tm5bTDH0.d.mts +0 -38
  108. package/dist/Projects.d.mts +0 -3
  109. package/dist/Projects.mjs +0 -65
  110. package/dist/Projects.mjs.map +0 -1
  111. package/dist/Recordings-B9k5aODB.d.mts +0 -27
  112. package/dist/Recordings.d.mts +0 -3
  113. package/dist/Recordings.mjs +0 -144
  114. package/dist/Recordings.mjs.map +0 -1
  115. package/dist/References-DOH3Wu44.d.mts +0 -34
  116. package/dist/References.d.mts +0 -3
  117. package/dist/References.mjs +0 -33
  118. package/dist/References.mjs.map +0 -1
  119. package/dist/Replays-mV93WGtx.d.mts +0 -27
  120. package/dist/Replays.d.mts +0 -3
  121. package/dist/Replays.mjs +0 -107
  122. package/dist/Replays.mjs.map +0 -1
  123. package/dist/Resource-J7Kkk5mu.mjs +0 -54
  124. package/dist/Resource-J7Kkk5mu.mjs.map +0 -1
  125. package/dist/Search-B64e7g-h.d.mts +0 -37
  126. package/dist/Search.d.mts +0 -3
  127. package/dist/Search.mjs +0 -46
  128. package/dist/Search.mjs.map +0 -1
  129. package/dist/SessionData-5xYZDshJ.d.mts +0 -38
  130. package/dist/SessionData.d.mts +0 -3
  131. package/dist/SessionData.mjs +0 -48
  132. package/dist/SessionData.mjs.map +0 -1
  133. package/dist/Sessions-D2H5m6rF.mjs +0 -260
  134. package/dist/Sessions-D2H5m6rF.mjs.map +0 -1
  135. package/dist/Sessions-oJEUmZth.d.mts +0 -69
  136. package/dist/Sessions.d.mts +0 -4
  137. package/dist/Sessions.mjs +0 -3
  138. package/dist/Testing.d.mts +0 -119
  139. package/dist/Testing.mjs +0 -206
  140. package/dist/Testing.mjs.map +0 -1
  141. package/dist/TransferPolicy-DQ06i7SZ.mjs +0 -25
  142. package/dist/TransferPolicy-DQ06i7SZ.mjs.map +0 -1
  143. package/dist/Transfers-GVqzrDWl.d.mts +0 -89
  144. package/dist/Transfers.d.mts +0 -3
  145. package/dist/Transfers.mjs +0 -85
  146. package/dist/Transfers.mjs.map +0 -1
  147. package/dist/Uploads-C2_bACgv.d.mts +0 -28
  148. package/dist/Uploads.d.mts +0 -3
  149. package/dist/Uploads.mjs +0 -105
  150. package/dist/Uploads.mjs.map +0 -1
  151. package/dist/Webhooks-BoeRAxzG.d.mts +0 -59
  152. package/dist/Webhooks.d.mts +0 -3
  153. package/dist/Webhooks.mjs +0 -134
  154. package/dist/Webhooks.mjs.map +0 -1
  155. package/dist/WriterFacts-BBJRDZYY.d.mts +0 -54
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Browserbase-FDltiz36.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 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\n extends\n Options,\n Pick<\n Supervisor.Options<BrowserError | BrowserbaseError | ContextHeld, BrowserbaseClient>,\n \"reopen\" | \"rotateBefore\" | \"waitTimeout\"\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}\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: BrowserError | BrowserbaseError | ContextHeld) =>\n error._tag === \"BrowserbaseError\" && !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 const supervise = (options: SuperviseOptions = {}) =>\n 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.suspend(() =>\n start(options, keep === undefined ? undefined : { name: keep, adopt: !opened }),\n ).pipe(\n Effect.tap(() =>\n Effect.sync(() => {\n opened = true;\n }),\n ),\n Effect.withSpan(\"Browserbase.open\", {}, { captureStackTrace: false }),\n ),\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 });\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":"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"}
@@ -0,0 +1,105 @@
1
+ import { t as BrowserbaseError } from "./BrowserbaseError-D1EOrLNc.mjs";
2
+ import { f as Session, n as BrowserbaseClient, p as SessionOptions } from "./BrowserbaseClient-CtAQ2rg4.mjs";
3
+ import { ContextHeld, ContextLease } from "./ContextLease.mjs";
4
+ import { Duration, Effect, Layer, Scope } from "effect";
5
+ import * as Browser from "effect-browser/Browser";
6
+ import { BrowserError } from "effect-browser/BrowserError";
7
+ import * as Supervisor from "effect-browser/Supervisor";
8
+ declare namespace Browserbase_d_exports {
9
+ export { Hosted, Options, SuperviseOptions, attach, layer, open, reconcile, supervise, verifyContext };
10
+ }
11
+ export interface Options extends Browser.Options {
12
+ readonly session?: SessionOptions | undefined;
13
+ /** Bound on connecting to the session. Defaults to 30 seconds. */
14
+ readonly connectTimeoutMillis?: number | undefined;
15
+ /**
16
+ * How long a persisting session's context stays held after the session ends, for its save to
17
+ * land. Defaults to 10 seconds, after which hosted checks have read a save back.
18
+ */
19
+ readonly contextSettle?: Duration.Input | undefined;
20
+ /**
21
+ * Run the pages' screencasts on a second connection to the session, which carries nothing else,
22
+ * so that a frame never waits behind a large message, such as an upload or a read's answer, on
23
+ * the connection that drives the page. Defaults to true.
24
+ */
25
+ readonly captureConnection?: boolean | undefined;
26
+ }
27
+ /** A browser on a Browserbase session. */
28
+ export interface Hosted {
29
+ readonly browser: Browser.Service;
30
+ readonly session: Session;
31
+ /**
32
+ * Release the session and confirm it ended, once: `open`'s scope runs it as it closes, while
33
+ * `attach`'s only disconnects. It disconnects `browser` first, which is lost as `released`, so a
34
+ * call in flight or a capture's reader is told so. Asked again, it reports the same outcome.
35
+ */
36
+ readonly release: Effect.Effect<Supervisor.Released>;
37
+ }
38
+ /**
39
+ * Create a session and open a `Browser` on it, for as long as the scope is open. If opening
40
+ * fails, the session and context are released then, so a retry in the same scope can take them.
41
+ * A persisting open holds its context through the `ContextLease`; a session that may still save
42
+ * to it, as one whose release was left `Unconfirmed` or whose create's answer was lost, is ended
43
+ * first, and the open fails with `ContextHeld` while that can't be confirmed. A lost create's own
44
+ * open looks for its session by the create's nonce, within `orphanSearch`, ends it, then fails with
45
+ * the create's error. `release` disconnects the browser before it asks Browserbase to end the
46
+ * session, so what fails meanwhile says it was released.
47
+ */
48
+ export declare const open: (options?: Options | undefined) => Effect.Effect<{
49
+ browser: Browser.Service;
50
+ session: Session;
51
+ release: Effect.Effect<Supervisor.Settled | Supervisor.Unconfirmed, never, never>;
52
+ }, BrowserError | BrowserbaseError | ContextHeld, BrowserbaseClient | ContextLease | Scope.Scope>;
53
+ /**
54
+ * Open a `Browser` on a session that already runs, such as a `keepAlive` session another process
55
+ * opened. This is resume: its pages keep their ids, their CDP target ids, so `browser.page(id)`
56
+ * finds a page stored before. Closing the scope disconnects and leaves the session running;
57
+ * `release` ends it. A session that has ended fails `Closed` by the session. It holds no context.
58
+ */
59
+ export declare const attach: (sessionId: string, options?: Options | undefined) => Effect.Effect<{
60
+ browser: Browser.Service;
61
+ session: Session;
62
+ release: Effect.Effect<Supervisor.Settled | Supervisor.Unconfirmed, never, never>;
63
+ }, BrowserError | BrowserbaseError, BrowserbaseClient | Scope.Scope>;
64
+ /**
65
+ * End a stored context's sessions, the ones `open` labelled as writing to it, and let the context
66
+ * go once they are confirmed ended and its save has settled. `open` does this itself when a writer
67
+ * before it may still run; `reconcile` does it without opening, as for sessions another process
68
+ * left running. It holds the context through the `ContextLease`, so it waits for a writer. A
69
+ * session still running at the deadline makes it `Unconfirmed`, and leaves the context unsettled,
70
+ * as a failure does.
71
+ */
72
+ export declare const reconcile: (contextId: string, options?: {
73
+ readonly contextSettle?: Duration.Input | undefined;
74
+ } | undefined) => Effect.Effect<Supervisor.Settled | Supervisor.Unconfirmed, BrowserbaseError | ContextHeld, BrowserbaseClient | ContextLease>;
75
+ /**
76
+ * Read a stored context back, as a login: a session that loads it and saves nothing runs `check`
77
+ * on its browser, and is released. The context is held through the `ContextLease` meanwhile, so
78
+ * the read never runs beside a writer, which a site could sign out, and it reads what the last
79
+ * writer saved, once that save settled. A session a writer before may have left saving to it is
80
+ * ended first, as for `open`.
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 extends Options, Pick<Supervisor.Options<BrowserError | BrowserbaseError | ContextHeld, BrowserbaseClient>, "reopen" | "rotateBefore" | "waitTimeout"> {
84
+ /**
85
+ * Keep the session past the supervisor's scope, under this name: 1 to 64 letters, digits, `_`,
86
+ * `.`, `:` or `-`. Each session is created with `keepAlive` and labelled `keptAs: <keep>` in its
87
+ * user metadata. Closing the scope only disconnects the current one, published as `Kept`, and
88
+ * the first generation of the next `supervise` under the same name adopts it, with its pages,
89
+ * rather than creating a session; other sessions kept under it are ended. `retire` releases. A
90
+ * kept session bills until it is adopted and released, or until its timeout ends it.
91
+ */
92
+ readonly keep?: string | undefined;
93
+ }
94
+ /**
95
+ * Keep Browserbase sessions open as `Supervisor` generations, each a new session made from
96
+ * `session`. Sessions that persist to a stored context are exclusive: a rotation releases the
97
+ * current one, and its context's save settles, before the next one opens. An open Browserbase
98
+ * refused, as for a bad key or an invalid request, is `Down` at once. With `keep`, closing the
99
+ * scope leaves the current session running for the next `supervise` under that name to adopt.
100
+ */
101
+ export declare const supervise: (options?: SuperviseOptions) => Effect.Effect<Supervisor.Supervisor, never, BrowserbaseClient | ContextLease | Scope.Scope>;
102
+ export declare const layer: (options?: Options) => Layer.Layer<Browser.Browser, BrowserError | BrowserbaseError | ContextHeld, BrowserbaseClient | ContextLease>;
103
+ //#endregion
104
+ export { Browserbase_d_exports as t };
105
+ //# sourceMappingURL=Browserbase.d.mts.map
@@ -0,0 +1,3 @@
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-FDltiz36.mjs";
3
+ export { attach, layer, open, reconcile, supervise, verifyContext };
@@ -0,0 +1,195 @@
1
+ import { t as BrowserbaseError } from "./BrowserbaseError-D1EOrLNc.mjs";
2
+ import { Config, Context, Duration, Effect, Layer, Redacted, Schema } from "effect";
3
+ import { HttpClient } from "effect/http";
4
+ declare namespace BrowserbaseClient_d_exports {
5
+ export { BrowserSettings, BrowserbaseClient, Extension, FetchOptions, FetchedPage, LiveView, Options, ProxyRule, SearchResult, Service, Session, SessionOptions, StoredContext, defaultBaseUrl, layer, layerConfig, make };
6
+ }
7
+ declare const defaultBaseUrl = "https://api.browserbase.com";
8
+ declare const Session_base: Schema.Class<Session, Schema.Struct<{
9
+ readonly id: Schema.String;
10
+ /** `PENDING`, `RUNNING`, `ERROR`, `TIMED_OUT` or `COMPLETED`, kept open for new values. */
11
+ readonly status: Schema.String;
12
+ readonly region: Schema.String;
13
+ readonly keepAlive: Schema.Boolean;
14
+ readonly createdAt: Schema.String;
15
+ readonly expiresAt: Schema.String;
16
+ readonly endedAt: Schema.optional<Schema.String>;
17
+ readonly contextId: Schema.optional<Schema.String>;
18
+ readonly proxyBytes: Schema.optional<Schema.Finite>;
19
+ readonly userMetadata: Schema.optional<Schema.$Record<Schema.String, Schema.Unknown>>;
20
+ /** The CDP WebSocket address, a credential. Only create and get return it. */
21
+ readonly connectUrl: Schema.optional<Schema.RedactedFromValue<Schema.String>>;
22
+ }>, {}>;
23
+ declare class Session extends Session_base {}
24
+ declare const LiveView_base: Schema.Class<LiveView, Schema.Struct<{
25
+ /** The active tab, without browser chrome: suited to an iframe. */
26
+ readonly debuggerFullscreenUrl: Schema.RedactedFromValue<Schema.String>;
27
+ readonly debuggerUrl: Schema.RedactedFromValue<Schema.String>;
28
+ readonly pages: Schema.$Array<Schema.Struct<{
29
+ readonly id: Schema.String;
30
+ readonly url: Schema.String;
31
+ readonly title: Schema.String;
32
+ readonly debuggerFullscreenUrl: Schema.RedactedFromValue<Schema.String>;
33
+ }>>;
34
+ }>, {}>;
35
+ /** Links that let a person watch and control a running session. They are credentials. */
36
+ declare class LiveView extends LiveView_base {}
37
+ declare const StoredContext_base: Schema.Class<StoredContext, Schema.Struct<{
38
+ readonly id: Schema.String;
39
+ readonly name: Schema.optional<Schema.String>;
40
+ /** `getContext` returns the timestamps; `createContext` does not. */
41
+ readonly createdAt: Schema.optional<Schema.String>;
42
+ readonly updatedAt: Schema.optional<Schema.String>;
43
+ }>, {}>;
44
+ /** Browser state (cookies, storage, cache) kept by Browserbase for sessions to load and save. */
45
+ declare class StoredContext extends StoredContext_base {}
46
+ declare const Extension_base: Schema.Class<Extension, Schema.Struct<{
47
+ readonly id: Schema.String;
48
+ readonly fileName: Schema.String;
49
+ readonly createdAt: Schema.String;
50
+ readonly updatedAt: Schema.String;
51
+ }>, {}>;
52
+ /** A Chrome extension uploaded to the project, which sessions load when created with its id. */
53
+ declare class Extension extends Extension_base {}
54
+ declare const SearchResult_base: Schema.Class<SearchResult, Schema.Struct<{
55
+ readonly url: Schema.String;
56
+ readonly title: Schema.String;
57
+ readonly author: Schema.optional<Schema.String>;
58
+ readonly publishedDate: Schema.optional<Schema.String>;
59
+ }>, {}>;
60
+ declare class SearchResult extends SearchResult_base {}
61
+ declare const FetchedPage_base: Schema.Class<FetchedPage, Schema.Struct<{
62
+ readonly statusCode: Schema.Finite;
63
+ readonly contentType: Schema.String;
64
+ readonly headers: Schema.$Record<Schema.String, Schema.String>;
65
+ /** Text for the `raw` and `markdown` formats; the extracted object for `json`. */
66
+ readonly content: Schema.Union<readonly [Schema.String, Schema.$Record<Schema.String, Schema.Unknown>]>;
67
+ }>, {}>;
68
+ /** A page fetched without a browser. */
69
+ declare class FetchedPage extends FetchedPage_base {}
70
+ /** A session create request, as Browserbase's API reference describes it. */
71
+ interface SessionOptions {
72
+ /** Defaults to the API key's project. */
73
+ readonly projectId?: string | undefined;
74
+ /** An uploaded extension for the browser to load. It makes the session slower to start. */
75
+ readonly extensionId?: string | undefined;
76
+ /** Seconds until Browserbase ends the session, from 60 to 21,600. Defaults to the project's. */
77
+ readonly timeout?: number | undefined;
78
+ /** Keep the session running after every client disconnects, until released or timed out. */
79
+ readonly keepAlive?: boolean | undefined;
80
+ readonly region?: "us-west-2" | "us-east-1" | "eu-central-1" | "ap-southeast-1" | undefined;
81
+ /** `true` for Browserbase's proxies, or rules per domain. */
82
+ readonly proxies?: boolean | ReadonlyArray<ProxyRule> | undefined;
83
+ /** Labels that `listSessions` can query. */
84
+ readonly userMetadata?: Readonly<Record<string, unknown>> | undefined;
85
+ readonly browserSettings?: BrowserSettings | undefined;
86
+ }
87
+ /** Browser settings. Left unset, each takes Browserbase's default. */
88
+ interface BrowserSettings {
89
+ /**
90
+ * Load a stored context. With `persist`, Browserbase saves the session's changes back to it once
91
+ * the session ends; `Browserbase.open` lets one such session at a time write to each context.
92
+ */
93
+ readonly context?: {
94
+ readonly id: string;
95
+ readonly persist?: boolean | undefined;
96
+ } | undefined;
97
+ readonly viewport?: {
98
+ readonly width: number;
99
+ readonly height: number;
100
+ } | undefined;
101
+ readonly blockAds?: boolean | undefined;
102
+ /** Browserbase solves captchas unless this is false. */
103
+ readonly solveCaptchas?: boolean | undefined;
104
+ /** Browserbase records the session for replay unless this is false. */
105
+ readonly recordSession?: boolean | undefined;
106
+ /** Browserbase keeps the session's logs unless this is false. */
107
+ readonly logSession?: boolean | undefined;
108
+ /** Verified browser mode, on plans that include it. */
109
+ readonly verified?: boolean | undefined;
110
+ readonly os?: "windows" | "mac" | "linux" | "mobile" | "tablet" | undefined;
111
+ /** Restrict top-level navigation to these domains and their subdomains. */
112
+ readonly allowedDomains?: ReadonlyArray<string> | undefined;
113
+ readonly ignoreCertificateErrors?: boolean | undefined;
114
+ }
115
+ type ProxyRule = {
116
+ readonly type: "browserbase";
117
+ readonly geolocation?: {
118
+ readonly country: string;
119
+ readonly state?: string | undefined;
120
+ readonly city?: string | undefined;
121
+ } | undefined;
122
+ readonly domainPattern?: string | undefined;
123
+ } | {
124
+ readonly type: "external";
125
+ readonly server: string;
126
+ readonly username?: string | undefined;
127
+ readonly password?: string | undefined;
128
+ readonly domainPattern?: string | undefined;
129
+ } | {
130
+ readonly type: "none";
131
+ readonly domainPattern?: string | undefined;
132
+ };
133
+ interface FetchOptions {
134
+ /** `raw` (the default) returns the body as is; `json` needs `schema`. */
135
+ readonly format?: "raw" | "markdown" | "json" | undefined;
136
+ /** JSON Schema of the object to extract with the `json` format. */
137
+ readonly schema?: Readonly<Record<string, unknown>> | undefined;
138
+ readonly allowRedirects?: boolean | undefined;
139
+ readonly allowInsecureSsl?: boolean | undefined;
140
+ readonly proxies?: boolean | undefined;
141
+ }
142
+ interface Service {
143
+ readonly createSession: (options?: SessionOptions) => Effect.Effect<Session, BrowserbaseError>;
144
+ readonly getSession: (id: string) => Effect.Effect<Session, BrowserbaseError>;
145
+ /** Sessions with the given status, or all. `query` filters on user metadata, in Browserbase's syntax. */
146
+ readonly listSessions: (options?: {
147
+ readonly status?: string | undefined;
148
+ readonly query?: string | undefined;
149
+ }) => Effect.Effect<ReadonlyArray<Session>, BrowserbaseError>;
150
+ /** End the session now, which stops its billing. Ending an ended session succeeds. */
151
+ readonly releaseSession: (id: string) => Effect.Effect<void, BrowserbaseError>;
152
+ /** Live view links. They last `expiresInSeconds`, or as long as the session. */
153
+ readonly liveView: (id: string, options?: {
154
+ readonly expiresInSeconds?: number | undefined;
155
+ }) => Effect.Effect<LiveView, BrowserbaseError>;
156
+ readonly createContext: (options?: {
157
+ readonly name?: string | undefined;
158
+ }) => Effect.Effect<StoredContext, BrowserbaseError>;
159
+ readonly getContext: (id: string) => Effect.Effect<StoredContext, BrowserbaseError>;
160
+ /** Delete a stored context for good. Sessions can no longer load it. */
161
+ readonly deleteContext: (id: string) => Effect.Effect<void, BrowserbaseError>;
162
+ /**
163
+ * Upload a Chrome extension: a zip of at most 100 MB with `manifest.json` at its root. Create a
164
+ * session with the returned id as `extensionId` to load it.
165
+ */
166
+ readonly uploadExtension: (archive: Uint8Array, options?: {
167
+ readonly fileName?: string | undefined;
168
+ }) => Effect.Effect<Extension, BrowserbaseError>;
169
+ readonly getExtension: (id: string) => Effect.Effect<Extension, BrowserbaseError>;
170
+ readonly deleteExtension: (id: string) => Effect.Effect<void, BrowserbaseError>;
171
+ /** Search the web for up to `results` hits, from 1 to 25. Defaults to 10. */
172
+ readonly search: (query: string, options?: {
173
+ readonly results?: number | undefined;
174
+ }) => Effect.Effect<ReadonlyArray<SearchResult>, BrowserbaseError>;
175
+ readonly fetch: (url: string, options?: FetchOptions) => Effect.Effect<FetchedPage, BrowserbaseError>;
176
+ }
177
+ declare const BrowserbaseClient_base: Context.ServiceClass<BrowserbaseClient, "effect-browserbase/BrowserbaseClient", Service>;
178
+ declare class BrowserbaseClient extends BrowserbaseClient_base {}
179
+ interface Options {
180
+ readonly apiKey: Redacted.Redacted<string>;
181
+ /** Defaults to `https://api.browserbase.com`. */
182
+ readonly baseUrl?: string | undefined;
183
+ /** Bound on each request attempt, including reading its answer. Defaults to 60 seconds. */
184
+ readonly requestTimeout?: Duration.Input | undefined;
185
+ }
186
+ declare const make: (options: Options) => Effect.Effect<Service, never, HttpClient.HttpClient>;
187
+ declare const layer: (options: Options) => Layer.Layer<BrowserbaseClient, never, HttpClient.HttpClient>;
188
+ /** The client configured from `BROWSERBASE_API_KEY` and, optionally, `BROWSERBASE_BASE_URL`. */
189
+ declare const layerConfig: (options?: {
190
+ readonly apiKey?: Config.Config<Redacted.Redacted<string>> | undefined;
191
+ readonly baseUrl?: Config.Config<string> | undefined;
192
+ }) => Layer.Layer<BrowserbaseClient, Config.ConfigError, HttpClient.HttpClient>;
193
+ //#endregion
194
+ export { layerConfig as _, FetchOptions as a, Options as c, Service as d, Session as f, layer as g, defaultBaseUrl as h, Extension as i, ProxyRule as l, StoredContext as m, BrowserbaseClient as n, FetchedPage as o, SessionOptions as p, BrowserbaseClient_d_exports as r, LiveView as s, BrowserSettings as t, SearchResult as u, make as v };
195
+ //# sourceMappingURL=BrowserbaseClient-CtAQ2rg4.d.mts.map
@@ -0,0 +1,2 @@
1
+ import { _ as layerConfig, a as FetchOptions, c as Options, d as Service, f as Session, g as layer, h as defaultBaseUrl, i as Extension, l as ProxyRule, m as StoredContext, n as BrowserbaseClient, o as FetchedPage, p as SessionOptions, s as LiveView, t as BrowserSettings, u as SearchResult, v as make } from "./BrowserbaseClient-CtAQ2rg4.mjs";
2
+ export { BrowserSettings, BrowserbaseClient, Extension, FetchOptions, FetchedPage, LiveView, Options, ProxyRule, SearchResult, Service, Session, SessionOptions, StoredContext, defaultBaseUrl, layer, layerConfig, make };
@@ -0,0 +1,190 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
+ import { BrowserbaseError, Decode, InvalidRequest, NotFound, RateLimited, Status, Transport, Unauthorized, isTransient } from "./BrowserbaseError.mjs";
3
+ import { Config, Context, Duration, Effect, Exit, Layer, Option, Redacted, Schedule, Schema, flow, identity } from "effect";
4
+ import { FetchHttpClient, Headers, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http";
5
+ //#region src/BrowserbaseClient.ts
6
+ /**
7
+ * A small client for the Browserbase REST API: sessions, stored contexts, extensions, web search
8
+ * and page fetch.
9
+ *
10
+ * It runs on the `HttpClient` the application provides, such as `FetchHttpClient.layer`. The API
11
+ * key travels only in the `X-BB-API-Key` header and is redacted from logs and traces. Redirects
12
+ * are refused rather than followed, because following one would send the key wherever it points.
13
+ *
14
+ * Every request has a deadline, so a provider that never answers cannot hold a caller's scope open.
15
+ * Reads are retried twice on transient failures. Writes are not: a session create that fails in
16
+ * transit or misses its deadline may still have created the session, which then ends at its timeout.
17
+ *
18
+ * @since 0.3.0
19
+ */
20
+ var BrowserbaseClient_exports = /* @__PURE__ */ __exportAll({
21
+ BrowserbaseClient: () => BrowserbaseClient,
22
+ Extension: () => Extension,
23
+ FetchedPage: () => FetchedPage,
24
+ LiveView: () => LiveView,
25
+ SearchResult: () => SearchResult,
26
+ Session: () => Session,
27
+ StoredContext: () => StoredContext,
28
+ defaultBaseUrl: () => defaultBaseUrl,
29
+ layer: () => layer,
30
+ layerConfig: () => layerConfig,
31
+ make: () => make
32
+ });
33
+ const defaultBaseUrl = "https://api.browserbase.com";
34
+ var Session = class extends Schema.Class("effect-browserbase/Session")({
35
+ id: Schema.String,
36
+ /** `PENDING`, `RUNNING`, `ERROR`, `TIMED_OUT` or `COMPLETED`, kept open for new values. */
37
+ status: Schema.String,
38
+ region: Schema.String,
39
+ keepAlive: Schema.Boolean,
40
+ createdAt: Schema.String,
41
+ expiresAt: Schema.String,
42
+ endedAt: Schema.optional(Schema.String),
43
+ contextId: Schema.optional(Schema.String),
44
+ proxyBytes: Schema.optional(Schema.Finite),
45
+ userMetadata: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),
46
+ /** The CDP WebSocket address, a credential. Only create and get return it. */
47
+ connectUrl: Schema.optional(Schema.RedactedFromValue(Schema.String))
48
+ }) {};
49
+ /** Links that let a person watch and control a running session. They are credentials. */
50
+ var LiveView = class extends Schema.Class("effect-browserbase/LiveView")({
51
+ /** The active tab, without browser chrome: suited to an iframe. */
52
+ debuggerFullscreenUrl: Schema.RedactedFromValue(Schema.String),
53
+ debuggerUrl: Schema.RedactedFromValue(Schema.String),
54
+ pages: Schema.Array(Schema.Struct({
55
+ id: Schema.String,
56
+ url: Schema.String,
57
+ title: Schema.String,
58
+ debuggerFullscreenUrl: Schema.RedactedFromValue(Schema.String)
59
+ }))
60
+ }) {};
61
+ /** Browser state (cookies, storage, cache) kept by Browserbase for sessions to load and save. */
62
+ var StoredContext = class extends Schema.Class("effect-browserbase/StoredContext")({
63
+ id: Schema.String,
64
+ name: Schema.optional(Schema.String),
65
+ /** `getContext` returns the timestamps; `createContext` does not. */
66
+ createdAt: Schema.optional(Schema.String),
67
+ updatedAt: Schema.optional(Schema.String)
68
+ }) {};
69
+ /** A Chrome extension uploaded to the project, which sessions load when created with its id. */
70
+ var Extension = class extends Schema.Class("effect-browserbase/Extension")({
71
+ id: Schema.String,
72
+ fileName: Schema.String,
73
+ createdAt: Schema.String,
74
+ updatedAt: Schema.String
75
+ }) {};
76
+ var SearchResult = class extends Schema.Class("effect-browserbase/SearchResult")({
77
+ url: Schema.String,
78
+ title: Schema.String,
79
+ author: Schema.optional(Schema.String),
80
+ publishedDate: Schema.optional(Schema.String)
81
+ }) {};
82
+ /** A page fetched without a browser. */
83
+ var FetchedPage = class extends Schema.Class("effect-browserbase/FetchedPage")({
84
+ statusCode: Schema.Finite,
85
+ contentType: Schema.String,
86
+ headers: Schema.Record(Schema.String, Schema.String),
87
+ /** Text for the `raw` and `markdown` formats; the extracted object for `json`. */
88
+ content: Schema.Union([Schema.String, Schema.Record(Schema.String, Schema.Unknown)])
89
+ }) {};
90
+ var BrowserbaseClient = class extends Context.Service()("effect-browserbase/BrowserbaseClient") {};
91
+ const ids = /^[A-Za-z0-9_-]{1,128}$/;
92
+ const maxExtensionBytes = 104857600;
93
+ const ErrorBody = Schema.fromJsonString(Schema.Struct({ message: Schema.String }));
94
+ const SearchResponse = Schema.Struct({ results: Schema.Array(SearchResult) });
95
+ const CreatedId = Schema.Struct({ id: Schema.String.check(Schema.isPattern(ids)) });
96
+ const statusReason = (status, detail) => {
97
+ if (status < 200 || status >= 300 && status < 400) return new Status({
98
+ status,
99
+ detail: "redirected; redirects are refused so the API key stays with Browserbase"
100
+ });
101
+ if (status === 400) return new InvalidRequest({ detail });
102
+ if (status === 401 || status === 403) return new Unauthorized({ detail });
103
+ if (status === 404) return new NotFound({ detail });
104
+ if (status === 429) return new RateLimited({ detail });
105
+ return new Status({
106
+ status,
107
+ detail
108
+ });
109
+ };
110
+ /** A create's answer that did not decode though it named session `id`, released or not since. */
111
+ const undecoded = (detail, id, released) => new Decode({
112
+ detail: `${detail}; session ${id} ${released ? "was released" : "could not be released and ends at its timeout"}`,
113
+ released
114
+ });
115
+ /** Run the request with fetch's redirect mode set to manual, keeping any other fetch options. */
116
+ const refuseRedirects = (effect) => Effect.contextWith((context) => Effect.provideService(effect, FetchHttpClient.RequestInit, {
117
+ ...Context.getOrUndefined(context, FetchHttpClient.RequestInit),
118
+ redirect: "manual"
119
+ }));
120
+ const make = Effect.fnUntraced(function* (options) {
121
+ const http = (yield* HttpClient.HttpClient).pipe(HttpClient.mapRequest(flow(HttpClientRequest.prependUrl(options.baseUrl ?? "https://api.browserbase.com"), HttpClientRequest.setHeader("x-bb-api-key", Redacted.value(options.apiKey)), HttpClientRequest.acceptJson)), HttpClient.transformResponse(flow(refuseRedirects, Effect.updateService(Headers.CurrentRedactedNames, (names) => [...names, "x-bb-api-key"]))));
122
+ const failure = (operation, reason) => new BrowserbaseError({
123
+ operation,
124
+ reason
125
+ });
126
+ const requestTimeout = Duration.fromInputUnsafe(options.requestTimeout ?? Duration.seconds(60));
127
+ /** Send one request; on a success status, read the answer with `read`. */
128
+ const send = (operation, request, read) => http.execute(request).pipe(Effect.mapError((error) => failure(operation, new Transport({ detail: error.message }))), Effect.flatMap((response) => response.status >= 200 && response.status < 300 ? read(response) : response.text.pipe(Effect.map((text) => Option.getOrElse(Option.map(Schema.decodeOption(ErrorBody)(text), (body) => body.message), () => text.slice(0, 300))), Effect.orElseSucceed(() => ""), Effect.flatMap((detail) => Effect.fail(failure(operation, statusReason(response.status, detail)))))), Effect.timeoutOrElse({
129
+ duration: requestTimeout,
130
+ orElse: () => Effect.fail(failure(operation, new Transport({ detail: `no answer within ${Duration.format(requestTimeout)}` })))
131
+ }), request.method === "GET" ? Effect.retry({
132
+ while: isTransient,
133
+ times: 2,
134
+ schedule: Schedule.exponential("250 millis").pipe(Schedule.jittered)
135
+ }) : identity, Effect.withSpan(`Browserbase.${operation}`));
136
+ const json = (operation, schema) => (response) => HttpClientResponse.schemaBodyJson(schema)(response).pipe(Effect.mapError((error) => failure(operation, new Decode({ detail: error.message.split("\n")[0] ?? "" }))));
137
+ const ignoreBody = () => Effect.void;
138
+ const withBody = (operation, request, body) => HttpClientRequest.bodyJson(request, body).pipe(Effect.mapError((error) => failure(operation, new InvalidRequest({ detail: error.message }))));
139
+ const checkId = (operation, id) => ids.test(id) ? Effect.succeed(id) : Effect.fail(failure(operation, new InvalidRequest({ detail: `${JSON.stringify(id)} is not a Browserbase id` })));
140
+ const releaseSession = (id) => checkId("releaseSession", id).pipe(Effect.flatMap(() => withBody("releaseSession", HttpClientRequest.post(`/v1/sessions/${id}`), { status: "REQUEST_RELEASE" })), Effect.flatMap((request) => send("releaseSession", request, ignoreBody)));
141
+ const createSession = (body) => withBody("createSession", HttpClientRequest.post("/v1/sessions"), body).pipe(Effect.flatMap((request) => send("createSession", request, json("createSession", Schema.Unknown))), Effect.flatMap((answer) => Schema.decodeUnknownEffect(Session)(answer).pipe(Effect.catch((error) => {
142
+ const detail = error.message.split("\n")[0] ?? "";
143
+ return Option.match(Schema.decodeUnknownOption(CreatedId)(answer), {
144
+ onNone: () => Effect.fail(failure("createSession", new Decode({ detail }))),
145
+ onSome: ({ id }) => releaseSession(id).pipe(Effect.exit, Effect.flatMap((release) => Effect.fail(failure("createSession", undecoded(detail, id, Exit.isSuccess(release))))))
146
+ });
147
+ }))));
148
+ return BrowserbaseClient.of({
149
+ createSession: (body = {}) => createSession(body),
150
+ getSession: (id) => checkId("getSession", id).pipe(Effect.flatMap(() => send("getSession", HttpClientRequest.get(`/v1/sessions/${id}`), json("getSession", Session)))),
151
+ listSessions: (filter = {}) => send("listSessions", HttpClientRequest.get("/v1/sessions", { urlParams: {
152
+ ...filter.status === void 0 ? {} : { status: filter.status },
153
+ ...filter.query === void 0 ? {} : { q: filter.query }
154
+ } }), json("listSessions", Schema.Array(Session))),
155
+ releaseSession,
156
+ liveView: (id, options = {}) => checkId("liveView", id).pipe(Effect.flatMap(() => send("liveView", HttpClientRequest.get(`/v1/sessions/${id}/debug`, { urlParams: options.expiresInSeconds === void 0 ? {} : { expiresIn: options.expiresInSeconds } }), json("liveView", LiveView)))),
157
+ createContext: (body = {}) => withBody("createContext", HttpClientRequest.post("/v1/contexts"), body).pipe(Effect.flatMap((request) => send("createContext", request, json("createContext", StoredContext)))),
158
+ getContext: (id) => checkId("getContext", id).pipe(Effect.flatMap(() => send("getContext", HttpClientRequest.get(`/v1/contexts/${id}`), json("getContext", StoredContext)))),
159
+ deleteContext: (id) => checkId("deleteContext", id).pipe(Effect.flatMap(() => send("deleteContext", HttpClientRequest.delete(`/v1/contexts/${id}`), ignoreBody))),
160
+ uploadExtension: (archive, options = {}) => archive.byteLength === 0 || archive.byteLength > maxExtensionBytes ? Effect.fail(failure("uploadExtension", new InvalidRequest({ detail: `the archive has ${archive.byteLength} bytes; Browserbase takes 1 byte to 100 MB` }))) : Effect.suspend(() => {
161
+ const form = new FormData();
162
+ form.append("file", new Blob([new Uint8Array(archive)], { type: "application/zip" }), options.fileName ?? "extension.zip");
163
+ return send("uploadExtension", HttpClientRequest.post("/v1/extensions").pipe(HttpClientRequest.bodyFormData(form)), json("uploadExtension", Extension));
164
+ }),
165
+ getExtension: (id) => checkId("getExtension", id).pipe(Effect.flatMap(() => send("getExtension", HttpClientRequest.get(`/v1/extensions/${id}`), json("getExtension", Extension)))),
166
+ deleteExtension: (id) => checkId("deleteExtension", id).pipe(Effect.flatMap(() => send("deleteExtension", HttpClientRequest.delete(`/v1/extensions/${id}`), ignoreBody))),
167
+ search: (query, options = {}) => withBody("search", HttpClientRequest.post("/v1/search"), {
168
+ query,
169
+ ...options.results === void 0 ? {} : { numResults: options.results }
170
+ }).pipe(Effect.flatMap((request) => send("search", request, json("search", SearchResponse))), Effect.map((response) => response.results)),
171
+ fetch: (url, options = {}) => withBody("fetch", HttpClientRequest.post("/v1/fetch"), {
172
+ url,
173
+ ...options
174
+ }).pipe(Effect.flatMap((request) => send("fetch", request, json("fetch", FetchedPage))))
175
+ });
176
+ });
177
+ const layer = (options) => Layer.effect(BrowserbaseClient, make(options));
178
+ /** The client configured from `BROWSERBASE_API_KEY` and, optionally, `BROWSERBASE_BASE_URL`. */
179
+ const layerConfig = (options = {}) => Layer.effect(BrowserbaseClient, Effect.gen(function* () {
180
+ const apiKey = yield* options.apiKey ?? Config.Redacted("BROWSERBASE_API_KEY");
181
+ const baseUrl = yield* options.baseUrl ?? Config.String("BROWSERBASE_BASE_URL").pipe(Config.withDefault("https://api.browserbase.com"));
182
+ return yield* make({
183
+ apiKey,
184
+ baseUrl
185
+ });
186
+ }));
187
+ //#endregion
188
+ export { BrowserbaseClient, Extension, FetchedPage, LiveView, SearchResult, Session, StoredContext, defaultBaseUrl, layer, layerConfig, make, BrowserbaseClient_exports as t };
189
+
190
+ //# sourceMappingURL=BrowserbaseClient.mjs.map