effect-browserbase 0.2.0-beta.4 → 0.2.0-beta.6

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  `effect-browserbase` supplies Browserbase resources and hosted lifetimes to the shared browser runtime: account identity and transport, session, context and extension resources, one owned browser over Playwright/CDP — allocated or borrowed — with trusted registrations, modeled file selection, bounded live capture, explicit page holds, the provider's recordings, replays, uploads and website downloads, and the platform APIs outside a browser session (projects, certificates, Search, Fetch, Agents, Functions and webhooks).
4
4
 
5
- Its host supplies the required `effect-browser` peer, at the same coordinated `0.2.0-beta.4` version; it has no Effect Agent dependency. Install both packages explicitly so the provider and application share one runtime instance. Playwright is an optional peer of the shared runtime and is loaded only when a browser connects; artifact-only consumers do not need it. The Effect peer range is `^4.0.0-rc.117`, with rc.117 qualified. The package targets trusted Node and Bun hosts. It is published as a beta (`0.2.0-beta.0` on the `beta` dist-tag): hosted provider behavior requires separate validation, and ordinary tests never create a paid Browserbase session or invoke a paid model.
5
+ Its host supplies the required `effect-browser` peer, at the same coordinated `0.2.0-beta.6` version; it has no Effect Agent dependency. Install both packages explicitly so the provider and application share one runtime instance. Playwright is an optional peer of the shared runtime and is loaded only when a browser connects; artifact-only consumers do not need it. The Effect peer range is `^4.0.0-rc.117`, with rc.117 qualified. The package targets trusted Node and Bun hosts. It is published as a beta (`0.2.0-beta.0` on the `beta` dist-tag): hosted provider behavior requires separate validation, and ordinary tests never create a paid Browserbase session or invoke a paid model.
6
6
 
7
7
  ## One account, then resources
8
8
 
@@ -29,6 +29,8 @@ const account = Account.layerConfig({
29
29
 
30
30
  `ContextCoordination.withWriter` accepts a consumer-owned distributed lease backend and preserves the consumer's Effect error and environment types. A persisting allocation authenticates that live permit and reports its exact attempt, session and cleanup receipt before settlement. Unknown writers and unconfirmed persistence are quarantined. A terminal session does not establish that Context data finished synchronizing.
31
31
 
32
+ A quarantined Context stays refused in the process until `ContextCoordination.reconcile(reference, readback)` succeeds. It reads the provider's status for every session the quarantined writer recorded, requires each to be terminal, then runs your readback of the Context, and only then admits a writer again. It refuses a live writer, and no writer is admitted while it runs. It never ends a session: request the release yourself, wait for it to end, then reconcile. An allocation whose outcome stayed unknown names no session to check, so its Context stays refused until the process ends. Report the reconciliation to your backend afterwards: its own quarantine is separate. A lease `acquire` that fails leaves the Context free locally, because no allocation was attempted; the backend resolves whatever that failure left uncertain.
33
+
32
34
  ## Start with the result you need
33
35
 
34
36
  For the simplest post-session video path, opt in to Browserbase recording in the launch recipe:
@@ -3,7 +3,7 @@ import { AllocationError, ContextError, SessionError } from "./Errors.mjs";
3
3
  import { t as BrowserbaseClient } from "./Client-4RMKIpL2.mjs";
4
4
  import { t as compileLaunch } from "./Launch-cAdE2rrZ.mjs";
5
5
  import { CleanupIssue, CleanupResult } from "./Cleanup.mjs";
6
- import { i as requireContextWriterPermit } from "./ContextWriter-oKWFLHuP.mjs";
6
+ import { a as requireContextWriterPermit } from "./ContextWriter-CiEma24z.mjs";
7
7
  import { t as BrowserbaseSessions } from "./Sessions-BUoyPcPJ.mjs";
8
8
  import { t as connectionAddress } from "./Connection-sxyxtwlk.mjs";
9
9
  import { Cause, Clock, Crypto, Data, Effect, ErrorReporter, Exit, Option, Schema, Scope } from "effect";
@@ -232,4 +232,4 @@ const acquireRemote = Effect.fnUntraced(function* (options, local = noLocalConne
232
232
  //#endregion
233
233
  export { reported as a, noLocalConnection as i, reportCleanup as n, makeCleanup as r, acquireRemote as t };
234
234
 
235
- //# sourceMappingURL=Acquisition-CLN6lUeJ.mjs.map
235
+ //# sourceMappingURL=Acquisition-Ca4EE-Fg.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Acquisition-CLN6lUeJ.mjs","names":[],"sources":["../src/internal/session/Cleanup.ts","../src/internal/session/Diagnostics.ts","../src/internal/session/Acquisition.ts"],"sourcesContent":["import { Effect, Option } from \"effect\";\nimport { cleanupStep, noConnection, type ConnectionCleanup } from \"effect-browser/browser-runtime\";\n\nexport { reported } from \"effect-browser/browser-runtime\";\nexport type { ConnectionCleanup as LocalCleanup } from \"effect-browser/browser-runtime\";\n\nimport { CleanupIssue, CleanupResult } from \"../../Cleanup.ts\";\nimport type { SessionReference } from \"../../References.ts\";\nimport type { SessionStatus } from \"../../SessionData.ts\";\nimport type { BrowserbaseSessions } from \"../../Sessions.ts\";\n\nexport const noLocalConnection = noConnection;\n\n/** Internal limits, also injectable by deterministic failure tests. */\nexport interface CleanupLimits {\n readonly localStepMillis: number;\n readonly releaseMillis: number;\n readonly terminalMillis: number;\n}\n\nexport const defaultCleanupLimits: CleanupLimits = {\n localStepMillis: 3000,\n releaseMillis: 4000,\n terminalMillis: 4000,\n};\n\n/**\n * Close is one uninterruptible, bounded transaction over *local cleanup evidence*, not\n * a transaction over the remote browser. Each step observes its own Exit so failures\n * cannot suppress a later disconnect, release request, or exact-session status read.\n */\nexport const makeCleanup = Effect.fnUntraced(function* (\n reference: SessionReference,\n ownership: CleanupResult[\"ownership\"],\n sessions: BrowserbaseSessions[\"Service\"],\n local: ConnectionCleanup,\n report: (result: CleanupResult) => void,\n limits: CleanupLimits = defaultCleanupLimits,\n) {\n let latest: CleanupResult | undefined;\n\n const close = yield* Effect.cached(\n Effect.uninterruptible(\n Effect.gen(function* () {\n const issues: CleanupIssue[] = [];\n\n const step = <A, E>(\n name: CleanupIssue[\"step\"],\n action: Effect.Effect<A, E>,\n milliseconds: number,\n ) =>\n cleanupStep(action, milliseconds).pipe(\n Effect.tap((result) =>\n Effect.sync(() => {\n if (result._tag === \"Failure\")\n issues.push(CleanupIssue.make({ step: name, reason: result.reason }));\n }),\n ),\n );\n\n // The fence runs synchronously before interruptible native teardown begins.\n yield* step(\"fence\", local.fence, limits.localStepMillis);\n yield* step(\"capture\", local.capture, limits.localStepMillis);\n yield* step(\"initialization\", local.initialization, limits.localStepMillis);\n const disconnected = yield* step(\"disconnect\", local.disconnect, limits.localStepMillis);\n const localState = disconnected._tag === \"Success\" ? disconnected.value : \"failed\";\n\n let releaseRequested = false;\n let remote: CleanupResult[\"remote\"] = ownership === \"borrowed\" ? \"not-owned\" : \"unknown\";\n let observedStatus: SessionStatus | undefined;\n\n if (ownership === \"owned\") {\n const requested = yield* step(\n \"release\",\n sessions.requestRelease(reference),\n limits.releaseMillis,\n );\n\n releaseRequested = requested._tag === \"Success\";\n\n // A POST response is never substituted for a passive terminal-state observation.\n const terminal = yield* step(\n \"status\",\n sessions.waitForTerminal(reference, { timeoutMillis: limits.terminalMillis }),\n limits.terminalMillis,\n );\n\n if (terminal._tag === \"Success\") {\n remote = \"confirmed\";\n observedStatus = terminal.value.status;\n } else if (requested._tag === \"Success\") {\n remote = \"pending\";\n }\n }\n\n const result = CleanupResult.make({\n reference,\n ownership,\n releaseRequested,\n remote,\n local: localState,\n ...(observedStatus === undefined ? {} : { observedStatus }),\n issues,\n });\n\n Object.freeze(result.issues);\n latest = Object.freeze(result);\n report(latest);\n\n return latest;\n }),\n ),\n );\n\n return {\n close,\n result: Effect.sync(() => Option.fromNullishOr(latest)),\n };\n});\n","import { Cause, Data, Effect, ErrorReporter } from \"effect\";\n\nimport type { CleanupResult } from \"../../Cleanup.ts\";\nimport type { AllocationAttempt } from \"../../References.ts\";\n\n/**\n * Operator-visible evidence that a session's fate was not settled. It carries identity and\n * outcome labels only: no provider body, connection URL, credential or page content. The\n * transport deliberately disables tracing where credentials travel, so without this an\n * unconfirmed release or an allocation of unknown outcome would leave no trace for anyone who\n * did not register a callback.\n */\nclass SessionUnsettled extends Data.TaggedError(\"BrowserbaseSessionUnsettled\")<{\n readonly message: string;\n readonly details: Readonly<Record<string, string | number>>;\n}> {\n override readonly [ErrorReporter.severity] = \"Warn\" as const;\n\n override get [ErrorReporter.attributes]() {\n return this.details;\n }\n}\n\nconst surface = (message: string, details: Readonly<Record<string, string | number>>) =>\n Effect.logWarning(message).pipe(\n Effect.annotateLogs(details),\n Effect.andThen(ErrorReporter.report(Cause.fail(new SessionUnsettled({ message, details })))),\n );\n\n/** A borrowed scope never owns release, so only its local teardown can be unsettled. */\nexport const reportCleanup = (result: CleanupResult): Effect.Effect<void> => {\n const remoteUnsettled =\n result.ownership === \"owned\" && (result.remote !== \"confirmed\" || !result.releaseRequested);\n\n if (!remoteUnsettled && result.local !== \"failed\" && result.issues.length === 0)\n return Effect.void;\n\n return surface(\"Browserbase session cleanup ended without confirmation\", {\n projectId: result.reference.projectId,\n sessionId: result.reference.sessionId,\n ownership: result.ownership,\n remote: result.remote,\n local: result.local,\n observedStatus: result.observedStatus ?? \"unobserved\",\n issues: result.issues.map((issue) => `${issue.step}:${issue.reason}`).join(\",\") || \"none\",\n });\n};\n\n/** The provider may have allocated a session this process has no reference for. */\nexport const reportAllocationUncertain = (attempt: AllocationAttempt): Effect.Effect<void> =>\n surface(\"Browserbase allocation outcome is unknown\", {\n projectId: attempt.projectId,\n attemptId: attempt.attemptId,\n requestedAtMillis: attempt.requestedAtMillis,\n });\n","import { Clock, Crypto, Effect, Exit, Option, Schema, Scope } from \"effect\";\n\nimport type { CleanupResult } from \"../../Cleanup.ts\";\nimport { BrowserbaseClient } from \"../../Client.ts\";\nimport { AllocationError, ContextError, type ClientError, SessionError } from \"../../Errors.ts\";\nimport type { LaunchRecipe } from \"../../Launch.ts\";\nimport { type AllocationAttempt, Identifier, SessionReference } from \"../../References.ts\";\nimport { BrowserbaseSessions } from \"../../Sessions.ts\";\nimport { connectionAddress } from \"../provider/Connection.ts\";\nimport { compileLaunch } from \"../provider/Launch.ts\";\nimport {\n makeCleanup,\n noLocalConnection,\n reported,\n type CleanupLimits,\n type LocalCleanup,\n} from \"./Cleanup.ts\";\nimport { requireContextWriterPermit, type ContextWriterPermitInternal } from \"./ContextWriter.ts\";\nimport { reportAllocationUncertain, reportCleanup } from \"./Diagnostics.ts\";\nimport type { ContextWriterPermit } from \"./WriterFacts.ts\";\n\nconst AllocatedIdentity = Schema.Struct({ id: Identifier, projectId: Identifier });\n\nexport interface AcquisitionOptions {\n readonly launch: LaunchRecipe;\n readonly contextWriter?: ContextWriterPermit;\n readonly allocationDeadline?: number;\n /** Bounded host notification of the canonical facts. Reporting never changes them. */\n readonly onCleanup?: (result: CleanupResult) => Effect.Effect<void>;\n /** Exactly one notification when a creation attempt's effect on the provider is unknown. */\n readonly onAllocationUncertain?: (attempt: AllocationAttempt) => Effect.Effect<void>;\n}\n\n/**\n * The remote lease is registered before POST. Local connection work is supplied by\n * the same browser owner; the control plane never invents a second operation owner.\n */\nexport const acquireRemote = Effect.fnUntraced(function* (\n options: AcquisitionOptions,\n local: LocalCleanup = noLocalConnection,\n limits?: CleanupLimits,\n) {\n const client = yield* BrowserbaseClient;\n const sessions = yield* BrowserbaseSessions;\n const crypto = yield* Crypto.Crypto;\n const parent = yield* Scope.Scope;\n\n const launch = yield* compileLaunch(options.launch, {\n projectId: client.projectId,\n // Secure randomness is a platform precondition, so its failure is a defect, not an outcome.\n attemptId: yield* Effect.orDie(crypto.randomUUIDv4),\n requestedAtMillis: yield* Clock.currentTimeMillis,\n });\n\n const attempt = launch.attempt;\n let writer: ContextWriterPermitInternal | undefined;\n\n if (launch.context?.persist) {\n if (options.contextWriter === undefined) {\n return yield* ContextError.make({\n operation: \"writer-authority\",\n reason: \"authorization\",\n outcome: \"undispatched\",\n });\n }\n writer = yield* requireContextWriterPermit(options.contextWriter, {\n provider: \"browserbase\",\n projectId: client.projectId,\n contextId: launch.context.id,\n });\n } else if (options.contextWriter !== undefined) {\n return yield* ContextError.make({\n operation: \"writer-authority\",\n reason: \"configuration\",\n outcome: \"undispatched\",\n });\n }\n\n return yield* Effect.uninterruptibleMask((restore) =>\n Effect.gen(function* () {\n const resourceScope = yield* Scope.make();\n let reference: SessionReference | undefined;\n let admitted = false;\n let knownRejection = false;\n let closing = false;\n let cleanup: CleanupResult | undefined;\n\n let uncertainReported = false;\n\n const allocationUncertain = Effect.suspend(() => {\n if (uncertainReported) return Effect.void;\n uncertainReported = true;\n\n return reportAllocationUncertain(attempt).pipe(\n Effect.andThen(\n options.onAllocationUncertain === undefined\n ? Effect.void\n : reported(options.onAllocationUncertain(attempt)),\n ),\n );\n });\n\n const terminate = yield* Effect.cached(\n Effect.uninterruptible(\n Effect.gen(function* () {\n closing = true;\n if (reference === undefined) {\n if (admitted && !knownRejection) {\n writer?.uncertain(attempt);\n yield* allocationUncertain;\n }\n\n return;\n }\n\n const coordinator = yield* makeCleanup(\n reference,\n \"owned\",\n sessions,\n local,\n (result) => {\n cleanup = result;\n writer?.completed(attempt, result);\n },\n limits,\n );\n\n yield* coordinator.close;\n const result = cleanup;\n const notify = options.onCleanup;\n\n if (result !== undefined) {\n yield* reported(Effect.suspend(() => reportCleanup(result)));\n if (notify !== undefined) yield* reported(Effect.suspend(() => notify(result)));\n }\n }),\n ),\n );\n\n const closeScope = yield* Effect.cached(Scope.close(resourceScope, Exit.void));\n\n yield* Scope.addFinalizer(resourceScope, terminate);\n yield* Scope.addFinalizer(parent, closeScope);\n\n const failedAllocation = (error: ClientError): AllocationError => {\n knownRejection = error.outcome === \"rejected\" || error.outcome === \"undispatched\";\n if (knownRejection) writer?.rejected(attempt);\n else writer?.uncertain(attempt);\n const reason = error.reason;\n\n return AllocationError.make({\n attempt,\n outcome: knownRejection ? \"rejected\" : \"unknown\",\n reason:\n reason === \"authorization\" ||\n reason === \"rate-limited\" ||\n reason === \"configuration\" ||\n reason === \"transport\" ||\n reason === \"timeout\" ||\n reason === \"malformed\"\n ? reason\n : \"provider\",\n ...(error.status === undefined ? {} : { status: error.status }),\n ...(error.retryAfterMillis === undefined\n ? {}\n : { retryAfterMillis: error.retryAfterMillis }),\n });\n };\n\n const allocate = Effect.gen(function* () {\n if (writer !== undefined) yield* writer.recordAttempt(attempt);\n admitted = true;\n\n const raw = yield* restore(\n client.json(\"POST\", \"/v1/sessions\", launch.body, options.allocationDeadline),\n ).pipe(Effect.mapError(failedAllocation));\n\n const identity = yield* Schema.decodeUnknownEffect(AllocatedIdentity)(raw).pipe(\n Effect.mapError(() =>\n AllocationError.make({ attempt, outcome: \"unknown\", reason: \"malformed\" }),\n ),\n );\n\n // Save identity before interpreting any connection credentials or provider metadata.\n reference = Object.freeze(\n SessionReference.make({\n provider: \"browserbase\",\n projectId: identity.projectId,\n sessionId: identity.id,\n }),\n );\n writer?.recordSession(attempt, reference);\n if (reference.projectId !== client.projectId) {\n return yield* AllocationError.make({\n attempt,\n reference,\n outcome: \"unknown\",\n reason: \"malformed\",\n });\n }\n const ref = reference;\n\n return {\n reference: ref,\n attempt,\n launch,\n resourceScope,\n isClosed: () => closing,\n connection: (timeoutMillis: number) =>\n Effect.suspend(() =>\n closing\n ? Effect.fail(\n SessionError.make({\n operation: \"session-connect\",\n reason: \"expired\",\n outcome: \"undispatched\",\n }),\n )\n : connectionAddress(client, sessions, ref, timeoutMillis),\n ),\n release: closeScope.pipe(\n Effect.andThen(\n Effect.suspend(() =>\n cleanup === undefined\n ? Effect.die(new Error(\"Owned session closed without cleanup evidence\"))\n : Effect.succeed(cleanup),\n ),\n ),\n ),\n cleanupResult: Effect.sync(() => Option.fromNullishOr(cleanup)),\n };\n });\n\n return yield* allocate.pipe(\n Effect.onError(() => closeScope),\n Effect.onInterrupt(() => closeScope),\n );\n }),\n );\n});\n\nexport type RemoteAcquisition = Effect.Success<ReturnType<typeof acquireRemote>>;\n"],"mappings":"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"}
1
+ {"version":3,"file":"Acquisition-Ca4EE-Fg.mjs","names":[],"sources":["../src/internal/session/Cleanup.ts","../src/internal/session/Diagnostics.ts","../src/internal/session/Acquisition.ts"],"sourcesContent":["import { Effect, Option } from \"effect\";\nimport { cleanupStep, noConnection, type ConnectionCleanup } from \"effect-browser/browser-runtime\";\n\nexport { reported } from \"effect-browser/browser-runtime\";\nexport type { ConnectionCleanup as LocalCleanup } from \"effect-browser/browser-runtime\";\n\nimport { CleanupIssue, CleanupResult } from \"../../Cleanup.ts\";\nimport type { SessionReference } from \"../../References.ts\";\nimport type { SessionStatus } from \"../../SessionData.ts\";\nimport type { BrowserbaseSessions } from \"../../Sessions.ts\";\n\nexport const noLocalConnection = noConnection;\n\n/** Internal limits, also injectable by deterministic failure tests. */\nexport interface CleanupLimits {\n readonly localStepMillis: number;\n readonly releaseMillis: number;\n readonly terminalMillis: number;\n}\n\nexport const defaultCleanupLimits: CleanupLimits = {\n localStepMillis: 3000,\n releaseMillis: 4000,\n terminalMillis: 4000,\n};\n\n/**\n * Close is one uninterruptible, bounded transaction over *local cleanup evidence*, not\n * a transaction over the remote browser. Each step observes its own Exit so failures\n * cannot suppress a later disconnect, release request, or exact-session status read.\n */\nexport const makeCleanup = Effect.fnUntraced(function* (\n reference: SessionReference,\n ownership: CleanupResult[\"ownership\"],\n sessions: BrowserbaseSessions[\"Service\"],\n local: ConnectionCleanup,\n report: (result: CleanupResult) => void,\n limits: CleanupLimits = defaultCleanupLimits,\n) {\n let latest: CleanupResult | undefined;\n\n const close = yield* Effect.cached(\n Effect.uninterruptible(\n Effect.gen(function* () {\n const issues: CleanupIssue[] = [];\n\n const step = <A, E>(\n name: CleanupIssue[\"step\"],\n action: Effect.Effect<A, E>,\n milliseconds: number,\n ) =>\n cleanupStep(action, milliseconds).pipe(\n Effect.tap((result) =>\n Effect.sync(() => {\n if (result._tag === \"Failure\")\n issues.push(CleanupIssue.make({ step: name, reason: result.reason }));\n }),\n ),\n );\n\n // The fence runs synchronously before interruptible native teardown begins.\n yield* step(\"fence\", local.fence, limits.localStepMillis);\n yield* step(\"capture\", local.capture, limits.localStepMillis);\n yield* step(\"initialization\", local.initialization, limits.localStepMillis);\n const disconnected = yield* step(\"disconnect\", local.disconnect, limits.localStepMillis);\n const localState = disconnected._tag === \"Success\" ? disconnected.value : \"failed\";\n\n let releaseRequested = false;\n let remote: CleanupResult[\"remote\"] = ownership === \"borrowed\" ? \"not-owned\" : \"unknown\";\n let observedStatus: SessionStatus | undefined;\n\n if (ownership === \"owned\") {\n const requested = yield* step(\n \"release\",\n sessions.requestRelease(reference),\n limits.releaseMillis,\n );\n\n releaseRequested = requested._tag === \"Success\";\n\n // A POST response is never substituted for a passive terminal-state observation.\n const terminal = yield* step(\n \"status\",\n sessions.waitForTerminal(reference, { timeoutMillis: limits.terminalMillis }),\n limits.terminalMillis,\n );\n\n if (terminal._tag === \"Success\") {\n remote = \"confirmed\";\n observedStatus = terminal.value.status;\n } else if (requested._tag === \"Success\") {\n remote = \"pending\";\n }\n }\n\n const result = CleanupResult.make({\n reference,\n ownership,\n releaseRequested,\n remote,\n local: localState,\n ...(observedStatus === undefined ? {} : { observedStatus }),\n issues,\n });\n\n Object.freeze(result.issues);\n latest = Object.freeze(result);\n report(latest);\n\n return latest;\n }),\n ),\n );\n\n return {\n close,\n result: Effect.sync(() => Option.fromNullishOr(latest)),\n };\n});\n","import { Cause, Data, Effect, ErrorReporter } from \"effect\";\n\nimport type { CleanupResult } from \"../../Cleanup.ts\";\nimport type { AllocationAttempt } from \"../../References.ts\";\n\n/**\n * Operator-visible evidence that a session's fate was not settled. It carries identity and\n * outcome labels only: no provider body, connection URL, credential or page content. The\n * transport deliberately disables tracing where credentials travel, so without this an\n * unconfirmed release or an allocation of unknown outcome would leave no trace for anyone who\n * did not register a callback.\n */\nclass SessionUnsettled extends Data.TaggedError(\"BrowserbaseSessionUnsettled\")<{\n readonly message: string;\n readonly details: Readonly<Record<string, string | number>>;\n}> {\n override readonly [ErrorReporter.severity] = \"Warn\" as const;\n\n override get [ErrorReporter.attributes]() {\n return this.details;\n }\n}\n\nconst surface = (message: string, details: Readonly<Record<string, string | number>>) =>\n Effect.logWarning(message).pipe(\n Effect.annotateLogs(details),\n Effect.andThen(ErrorReporter.report(Cause.fail(new SessionUnsettled({ message, details })))),\n );\n\n/** A borrowed scope never owns release, so only its local teardown can be unsettled. */\nexport const reportCleanup = (result: CleanupResult): Effect.Effect<void> => {\n const remoteUnsettled =\n result.ownership === \"owned\" && (result.remote !== \"confirmed\" || !result.releaseRequested);\n\n if (!remoteUnsettled && result.local !== \"failed\" && result.issues.length === 0)\n return Effect.void;\n\n return surface(\"Browserbase session cleanup ended without confirmation\", {\n projectId: result.reference.projectId,\n sessionId: result.reference.sessionId,\n ownership: result.ownership,\n remote: result.remote,\n local: result.local,\n observedStatus: result.observedStatus ?? \"unobserved\",\n issues: result.issues.map((issue) => `${issue.step}:${issue.reason}`).join(\",\") || \"none\",\n });\n};\n\n/** The provider may have allocated a session this process has no reference for. */\nexport const reportAllocationUncertain = (attempt: AllocationAttempt): Effect.Effect<void> =>\n surface(\"Browserbase allocation outcome is unknown\", {\n projectId: attempt.projectId,\n attemptId: attempt.attemptId,\n requestedAtMillis: attempt.requestedAtMillis,\n });\n","import { Clock, Crypto, Effect, Exit, Option, Schema, Scope } from \"effect\";\n\nimport type { CleanupResult } from \"../../Cleanup.ts\";\nimport { BrowserbaseClient } from \"../../Client.ts\";\nimport { AllocationError, ContextError, type ClientError, SessionError } from \"../../Errors.ts\";\nimport type { LaunchRecipe } from \"../../Launch.ts\";\nimport { type AllocationAttempt, Identifier, SessionReference } from \"../../References.ts\";\nimport { BrowserbaseSessions } from \"../../Sessions.ts\";\nimport { connectionAddress } from \"../provider/Connection.ts\";\nimport { compileLaunch } from \"../provider/Launch.ts\";\nimport {\n makeCleanup,\n noLocalConnection,\n reported,\n type CleanupLimits,\n type LocalCleanup,\n} from \"./Cleanup.ts\";\nimport { requireContextWriterPermit, type ContextWriterPermitInternal } from \"./ContextWriter.ts\";\nimport { reportAllocationUncertain, reportCleanup } from \"./Diagnostics.ts\";\nimport type { ContextWriterPermit } from \"./WriterFacts.ts\";\n\nconst AllocatedIdentity = Schema.Struct({ id: Identifier, projectId: Identifier });\n\nexport interface AcquisitionOptions {\n readonly launch: LaunchRecipe;\n readonly contextWriter?: ContextWriterPermit;\n readonly allocationDeadline?: number;\n /** Bounded host notification of the canonical facts. Reporting never changes them. */\n readonly onCleanup?: (result: CleanupResult) => Effect.Effect<void>;\n /** Exactly one notification when a creation attempt's effect on the provider is unknown. */\n readonly onAllocationUncertain?: (attempt: AllocationAttempt) => Effect.Effect<void>;\n}\n\n/**\n * The remote lease is registered before POST. Local connection work is supplied by\n * the same browser owner; the control plane never invents a second operation owner.\n */\nexport const acquireRemote = Effect.fnUntraced(function* (\n options: AcquisitionOptions,\n local: LocalCleanup = noLocalConnection,\n limits?: CleanupLimits,\n) {\n const client = yield* BrowserbaseClient;\n const sessions = yield* BrowserbaseSessions;\n const crypto = yield* Crypto.Crypto;\n const parent = yield* Scope.Scope;\n\n const launch = yield* compileLaunch(options.launch, {\n projectId: client.projectId,\n // Secure randomness is a platform precondition, so its failure is a defect, not an outcome.\n attemptId: yield* Effect.orDie(crypto.randomUUIDv4),\n requestedAtMillis: yield* Clock.currentTimeMillis,\n });\n\n const attempt = launch.attempt;\n let writer: ContextWriterPermitInternal | undefined;\n\n if (launch.context?.persist) {\n if (options.contextWriter === undefined) {\n return yield* ContextError.make({\n operation: \"writer-authority\",\n reason: \"authorization\",\n outcome: \"undispatched\",\n });\n }\n writer = yield* requireContextWriterPermit(options.contextWriter, {\n provider: \"browserbase\",\n projectId: client.projectId,\n contextId: launch.context.id,\n });\n } else if (options.contextWriter !== undefined) {\n return yield* ContextError.make({\n operation: \"writer-authority\",\n reason: \"configuration\",\n outcome: \"undispatched\",\n });\n }\n\n return yield* Effect.uninterruptibleMask((restore) =>\n Effect.gen(function* () {\n const resourceScope = yield* Scope.make();\n let reference: SessionReference | undefined;\n let admitted = false;\n let knownRejection = false;\n let closing = false;\n let cleanup: CleanupResult | undefined;\n\n let uncertainReported = false;\n\n const allocationUncertain = Effect.suspend(() => {\n if (uncertainReported) return Effect.void;\n uncertainReported = true;\n\n return reportAllocationUncertain(attempt).pipe(\n Effect.andThen(\n options.onAllocationUncertain === undefined\n ? Effect.void\n : reported(options.onAllocationUncertain(attempt)),\n ),\n );\n });\n\n const terminate = yield* Effect.cached(\n Effect.uninterruptible(\n Effect.gen(function* () {\n closing = true;\n if (reference === undefined) {\n if (admitted && !knownRejection) {\n writer?.uncertain(attempt);\n yield* allocationUncertain;\n }\n\n return;\n }\n\n const coordinator = yield* makeCleanup(\n reference,\n \"owned\",\n sessions,\n local,\n (result) => {\n cleanup = result;\n writer?.completed(attempt, result);\n },\n limits,\n );\n\n yield* coordinator.close;\n const result = cleanup;\n const notify = options.onCleanup;\n\n if (result !== undefined) {\n yield* reported(Effect.suspend(() => reportCleanup(result)));\n if (notify !== undefined) yield* reported(Effect.suspend(() => notify(result)));\n }\n }),\n ),\n );\n\n const closeScope = yield* Effect.cached(Scope.close(resourceScope, Exit.void));\n\n yield* Scope.addFinalizer(resourceScope, terminate);\n yield* Scope.addFinalizer(parent, closeScope);\n\n const failedAllocation = (error: ClientError): AllocationError => {\n knownRejection = error.outcome === \"rejected\" || error.outcome === \"undispatched\";\n if (knownRejection) writer?.rejected(attempt);\n else writer?.uncertain(attempt);\n const reason = error.reason;\n\n return AllocationError.make({\n attempt,\n outcome: knownRejection ? \"rejected\" : \"unknown\",\n reason:\n reason === \"authorization\" ||\n reason === \"rate-limited\" ||\n reason === \"configuration\" ||\n reason === \"transport\" ||\n reason === \"timeout\" ||\n reason === \"malformed\"\n ? reason\n : \"provider\",\n ...(error.status === undefined ? {} : { status: error.status }),\n ...(error.retryAfterMillis === undefined\n ? {}\n : { retryAfterMillis: error.retryAfterMillis }),\n });\n };\n\n const allocate = Effect.gen(function* () {\n if (writer !== undefined) yield* writer.recordAttempt(attempt);\n admitted = true;\n\n const raw = yield* restore(\n client.json(\"POST\", \"/v1/sessions\", launch.body, options.allocationDeadline),\n ).pipe(Effect.mapError(failedAllocation));\n\n const identity = yield* Schema.decodeUnknownEffect(AllocatedIdentity)(raw).pipe(\n Effect.mapError(() =>\n AllocationError.make({ attempt, outcome: \"unknown\", reason: \"malformed\" }),\n ),\n );\n\n // Save identity before interpreting any connection credentials or provider metadata.\n reference = Object.freeze(\n SessionReference.make({\n provider: \"browserbase\",\n projectId: identity.projectId,\n sessionId: identity.id,\n }),\n );\n writer?.recordSession(attempt, reference);\n if (reference.projectId !== client.projectId) {\n return yield* AllocationError.make({\n attempt,\n reference,\n outcome: \"unknown\",\n reason: \"malformed\",\n });\n }\n const ref = reference;\n\n return {\n reference: ref,\n attempt,\n launch,\n resourceScope,\n isClosed: () => closing,\n connection: (timeoutMillis: number) =>\n Effect.suspend(() =>\n closing\n ? Effect.fail(\n SessionError.make({\n operation: \"session-connect\",\n reason: \"expired\",\n outcome: \"undispatched\",\n }),\n )\n : connectionAddress(client, sessions, ref, timeoutMillis),\n ),\n release: closeScope.pipe(\n Effect.andThen(\n Effect.suspend(() =>\n cleanup === undefined\n ? Effect.die(new Error(\"Owned session closed without cleanup evidence\"))\n : Effect.succeed(cleanup),\n ),\n ),\n ),\n cleanupResult: Effect.sync(() => Option.fromNullishOr(cleanup)),\n };\n });\n\n return yield* allocate.pipe(\n Effect.onError(() => closeScope),\n Effect.onInterrupt(() => closeScope),\n );\n }),\n );\n});\n\nexport type RemoteAcquisition = Effect.Success<ReturnType<typeof acquireRemote>>;\n"],"mappings":"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"}
package/dist/Agents.mjs CHANGED
@@ -4,7 +4,7 @@ import { t as BrowserbaseClient } from "./Client-4RMKIpL2.mjs";
4
4
  import { t as resource } from "./Resource-DBksC4zB.mjs";
5
5
  import { ProxyRule } from "./Launch.mjs";
6
6
  import { n as proxy } from "./Launch-cAdE2rrZ.mjs";
7
- import { n as isContextWriterBusy } from "./ContextWriter-oKWFLHuP.mjs";
7
+ import { r as isContextWriterBusy } from "./ContextWriter-CiEma24z.mjs";
8
8
  import { Clock, Context, Effect, Layer, Schema } from "effect";
9
9
  //#region src/Agents.ts
10
10
  const Timestamp = Schema.String.check(Schema.isMaxLength(64));
@@ -1,4 +1,4 @@
1
- import { t as acquireRemote } from "./Acquisition-CLN6lUeJ.mjs";
1
+ import { t as acquireRemote } from "./Acquisition-Ca4EE-Fg.mjs";
2
2
  import { Effect } from "effect";
3
3
  //#region src/Allocation.ts
4
4
  /**
@@ -6,7 +6,7 @@ import { isTerminalSessionStatus } from "./SessionData.mjs";
6
6
  import { a as issueLiveView, o as browserRequestFailure, t as BrowserbaseSessions } from "./Sessions-BUoyPcPJ.mjs";
7
7
  import { t as issuedUpload } from "./Issued-DejqoMYL.mjs";
8
8
  import { t as connectionAddress } from "./Connection-sxyxtwlk.mjs";
9
- import { a as reported, i as noLocalConnection, n as reportCleanup, r as makeCleanup, t as acquireRemote } from "./Acquisition-CLN6lUeJ.mjs";
9
+ import { a as reported, i as noLocalConnection, n as reportCleanup, r as makeCleanup, t as acquireRemote } from "./Acquisition-Ca4EE-Fg.mjs";
10
10
  import { BrowserbaseBrowserBinding } from "./BrowserBinding.mjs";
11
11
  import { Context, Crypto, Effect, Exit, Layer, Option, Schema, Scope } from "effect";
12
12
  import { BrowserError, Reasons } from "effect-browser/errors";
@@ -267,4 +267,4 @@ const projected = (options) => ({
267
267
  //#endregion
268
268
  export { BrowserbaseBrowser as t };
269
269
 
270
- //# sourceMappingURL=Browser-Dw0JFTaD.mjs.map
270
+ //# sourceMappingURL=Browser-BPcF550A.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Browser-Dw0JFTaD.mjs","names":[],"sources":["../src/internal/session/Attachment.ts","../src/internal/session/Browser.ts","../src/Browser.ts"],"sourcesContent":["import { Effect, Exit, Option, Scope } from \"effect\";\n\nimport type { CleanupResult } from \"../../Cleanup.ts\";\nimport { BrowserbaseClient } from \"../../Client.ts\";\nimport { SessionError } from \"../../Errors.ts\";\nimport type { SessionReference } from \"../../References.ts\";\nimport { isTerminalSessionStatus } from \"../../SessionData.ts\";\nimport { BrowserbaseSessions } from \"../../Sessions.ts\";\nimport { connectionAddress } from \"../provider/Connection.ts\";\nimport {\n makeCleanup,\n noLocalConnection,\n reported,\n type CleanupLimits,\n type LocalCleanup,\n} from \"./Cleanup.ts\";\nimport { reportCleanup } from \"./Diagnostics.ts\";\n\nexport interface AttachmentOptions {\n readonly reference: SessionReference;\n /** Bounded admission of a session the provider has not finished starting. */\n readonly pendingWaitMillis?: number;\n readonly onCleanup?: (result: CleanupResult) => Effect.Effect<void>;\n}\n\nconst failure = (reason: SessionError[\"reason\"]) =>\n SessionError.make({ operation: \"session-attach\", reason, outcome: \"undispatched\" });\n\n/**\n * Borrowing an already running session. This scope owns its local connection and nothing\n * else: no allocation attempt is made, no release is requested, and no Context-writer\n * authority is claimed. Whoever allocated the session keeps all three.\n */\nexport const attachRemote = Effect.fnUntraced(function* (\n options: AttachmentOptions,\n local: LocalCleanup = noLocalConnection,\n limits?: CleanupLimits,\n) {\n const client = yield* BrowserbaseClient;\n const sessions = yield* BrowserbaseSessions;\n const parent = yield* Scope.Scope;\n const pendingWaitMillis = options.pendingWaitMillis ?? 0;\n\n if (\n !Number.isSafeInteger(pendingWaitMillis) ||\n pendingWaitMillis < 0 ||\n pendingWaitMillis > 600_000\n )\n return yield* failure(\"configuration\");\n\n // The status read validates project authority before anything is borrowed. A terminal\n // session needs a fresh allocation from durable state, never a reattachment.\n const observed = yield* sessions.retrieve(options.reference);\n\n if (isTerminalSessionStatus(observed.status)) return yield* failure(\"expired\");\n if (observed.status !== \"RUNNING\") {\n if (pendingWaitMillis === 0) return yield* failure(\"active\");\n yield* sessions.waitUntilRunning(observed.reference, { timeoutMillis: pendingWaitMillis });\n }\n const reference = observed.reference;\n\n return yield* Effect.uninterruptible(\n Effect.gen(function* () {\n const resourceScope = yield* Scope.make();\n let closing = false;\n let cleanup: CleanupResult | undefined;\n\n const terminate = yield* Effect.cached(\n Effect.uninterruptible(\n Effect.gen(function* () {\n closing = true;\n\n const coordinator = yield* makeCleanup(\n reference,\n \"borrowed\",\n sessions,\n local,\n (result) => {\n cleanup = result;\n },\n limits,\n );\n\n yield* coordinator.close;\n const result = cleanup;\n const notify = options.onCleanup;\n\n if (result !== undefined) {\n yield* reported(Effect.suspend(() => reportCleanup(result)));\n if (notify !== undefined) yield* reported(Effect.suspend(() => notify(result)));\n }\n }),\n ),\n );\n\n const closeScope = yield* Effect.cached(Scope.close(resourceScope, Exit.void));\n\n // Teardown is registered before the first connection, exactly as an owned scope does.\n yield* Scope.addFinalizer(resourceScope, terminate);\n yield* Scope.addFinalizer(parent, closeScope);\n\n return {\n reference,\n status: observed,\n connection: (timeoutMillis: number) =>\n Effect.suspend(() =>\n closing\n ? Effect.fail(\n SessionError.make({\n operation: \"session-connect\",\n reason: \"expired\",\n outcome: \"undispatched\",\n }),\n )\n : // Credentials are fetched fresh: an expiry can race the caller's own read.\n connectionAddress(client, sessions, reference, timeoutMillis),\n ),\n release: closeScope.pipe(\n Effect.andThen(\n Effect.suspend(() =>\n cleanup === undefined\n ? Effect.die(new Error(\"Borrowed session closed without cleanup evidence\"))\n : Effect.succeed(cleanup),\n ),\n ),\n ),\n cleanupResult: Effect.sync(() => Option.fromNullishOr(cleanup)),\n };\n }),\n );\n});\n","import { type Crypto, Effect, Option, type Redacted } from \"effect\";\nimport type { Lifetime, Source } from \"effect-browser/browser-runtime\";\nimport { BrowserError, Reasons } from \"effect-browser/errors\";\n\nimport type { CleanupResult } from \"../../Cleanup.ts\";\nimport { BrowserbaseClient } from \"../../Client.ts\";\nimport type { AllocationError, ContextError, SessionError } from \"../../Errors.ts\";\nimport type { LaunchRecipe } from \"../../Launch.ts\";\nimport type { AllocationAttempt, SessionReference } from \"../../References.ts\";\nimport { BrowserbaseSessions } from \"../../Sessions.ts\";\nimport { issueLiveView, type LiveView } from \"../browser/LiveView.ts\";\nimport { browserRequestFailure } from \"../browser/RequestFailure.ts\";\nimport { acquireRemote } from \"./Acquisition.ts\";\nimport { attachRemote } from \"./Attachment.ts\";\nimport type { ContextWriterPermit } from \"./WriterFacts.ts\";\n\nexport interface RemoteLease extends Lifetime {\n readonly reference: SessionReference;\n readonly closeChecked: Effect.Effect<CleanupResult, BrowserError>;\n readonly attempt?: AllocationAttempt;\n readonly release: Effect.Effect<CleanupResult>;\n readonly cleanupResult: Effect.Effect<Option.Option<CleanupResult>>;\n readonly liveView: (ttl: number) => Effect.Effect<LiveView, BrowserError>;\n}\n\ntype RemoteSource<L extends Lifetime, E> = Source<\n L,\n E,\n BrowserbaseClient | BrowserbaseSessions | Crypto.Crypto\n>;\n\n/** A borrowed connection closes without requiring or requesting remote termination. */\nconst checkedCleanup = (\n close: Effect.Effect<CleanupResult>,\n): Effect.Effect<CleanupResult, BrowserError> =>\n close.pipe(\n Effect.filterOrFail(\n (result) =>\n result.local === \"closed\" &&\n result.issues.length === 0 &&\n (result.ownership === \"borrowed\"\n ? result.remote === \"not-owned\"\n : result.remote === \"confirmed\"),\n () =>\n BrowserError.make({\n operation: \"close\",\n reason: Reasons.Provider.make({}),\n outcome: \"unknown\",\n }),\n ),\n );\n\nconst withConnection = <\n A extends {\n readonly reference: SessionReference;\n readonly connection: (\n timeoutMillis: number,\n ) => Effect.Effect<Redacted.Redacted<string>, SessionError>;\n readonly release: Effect.Effect<CleanupResult>;\n readonly cleanupResult: Effect.Effect<Option.Option<CleanupResult>>;\n },\n>(\n acquired: A,\n) => ({\n ...acquired,\n connection: (timeoutMillis: number) =>\n acquired\n .connection(timeoutMillis)\n .pipe(Effect.mapError((error) => browserRequestFailure(\"connect\", error))),\n closeChecked: checkedCleanup(acquired.release),\n controlRetired: acquired.cleanupResult.pipe(\n Effect.map(\n (result) =>\n Option.isSome(result) &&\n result.value.ownership === \"owned\" &&\n result.value.remote === \"confirmed\",\n ),\n ),\n});\n\nexport interface OwnedLease extends RemoteLease {\n readonly attempt: AllocationAttempt;\n}\n\nexport interface OwnedOptions {\n /** The single provider-faithful launch description; the owner adds no second default body. */\n readonly launch: LaunchRecipe;\n /** Required for a persistent context; the writer permit, not this owner, holds that authority. */\n readonly contextWriter?: ContextWriterPermit;\n readonly onCleanup?: (result: CleanupResult) => Effect.Effect<void>;\n readonly onAllocationUncertain?: (attempt: AllocationAttempt) => Effect.Effect<void>;\n}\n\n/** Allocates the session, and therefore owns releasing it. */\nconst providerControls = (\n client: BrowserbaseClient[\"Service\"],\n sessions: BrowserbaseSessions[\"Service\"],\n reference: SessionReference,\n) => ({\n liveView: (ttl: number) => issueLiveView(client, reference, ttl),\n verifyReconnect: sessions.retrieve(reference).pipe(\n Effect.mapError((error) => browserRequestFailure(\"reconnect\", error)),\n Effect.flatMap((status) =>\n status.status === \"RUNNING\"\n ? Effect.void\n : Effect.fail(\n BrowserError.make({\n operation: \"reconnect\",\n reason: Reasons.Expired.make({}),\n outcome: \"undispatched\",\n }),\n ),\n ),\n ),\n});\n\nexport const ownedRemote =\n (\n options: OwnedOptions,\n ): RemoteSource<OwnedLease, AllocationError | BrowserError | ContextError> =>\n (local, lifetimeDeadline) =>\n Effect.gen(function* () {\n const client = yield* BrowserbaseClient;\n const sessions = yield* BrowserbaseSessions;\n\n const acquired = yield* acquireRemote(\n {\n launch: options.launch,\n ...(options.contextWriter === undefined ? {} : { contextWriter: options.contextWriter }),\n allocationDeadline: lifetimeDeadline,\n ...(options.onCleanup === undefined ? {} : { onCleanup: options.onCleanup }),\n ...(options.onAllocationUncertain === undefined\n ? {}\n : { onAllocationUncertain: options.onAllocationUncertain }),\n },\n local,\n );\n\n return {\n ...withConnection(acquired),\n ...providerControls(client, sessions, acquired.reference),\n };\n });\n\n/** Borrows a running session: local connection only, and never a release request. */\nexport const borrowedRemote =\n (options: {\n readonly reference: SessionReference;\n readonly pendingWaitMillis?: number;\n readonly onCleanup?: (result: CleanupResult) => Effect.Effect<void>;\n }): RemoteSource<RemoteLease, SessionError> =>\n (local) =>\n Effect.gen(function* () {\n const client = yield* BrowserbaseClient;\n const sessions = yield* BrowserbaseSessions;\n const acquired = yield* attachRemote(options, local);\n\n return {\n ...withConnection(acquired),\n ...providerControls(client, sessions, acquired.reference),\n };\n });\n","import {\n Context,\n Crypto,\n Effect,\n Layer,\n type Option,\n type Redacted,\n Schema,\n type Scope,\n} from \"effect\";\nimport type { BrowserSession, OpenOptions } from \"effect-browser/browser\";\nimport type {\n ActionResult,\n AutomationOptions,\n BrowserPolicy,\n ClickRequest,\n Observation,\n} from \"effect-browser/browser-data\";\nimport * as BrowserRuntime from \"effect-browser/browser-runtime\";\nimport {\n BrowserError,\n Reasons,\n type BrowserOperation,\n type InitializationError,\n} from \"effect-browser/errors\";\n\nimport { BrowserbaseBrowserBinding } from \"./BrowserBinding.ts\";\nimport type { CleanupResult } from \"./Cleanup.ts\";\nimport { BrowserbaseClient } from \"./Client.ts\";\nimport type { AllocationError, ContextError, SessionError } from \"./Errors.ts\";\nimport type { LiveView } from \"./internal/browser/LiveView.ts\";\nimport { isList } from \"./internal/List.ts\";\nimport { borrowedRemote, ownedRemote, type RemoteLease } from \"./internal/session/Browser.ts\";\nimport type { ContextWriterPermit } from \"./internal/session/WriterFacts.ts\";\nimport { issuedUpload } from \"./internal/upload/Issued.ts\";\nimport type { LaunchRecipe } from \"./Launch.ts\";\nimport type { AllocationAttempt, SessionReference } from \"./References.ts\";\nimport { BrowserbaseSessions } from \"./Sessions.ts\";\nimport { DownloadObservation, type SelectFilesRequest } from \"./Transfers.ts\";\n\nexport type { LiveView } from \"./internal/browser/LiveView.ts\";\nexport type { FileSelection, SelectFilesRequest } from \"./Transfers.ts\";\n\n/** Host configuration. Credentials live in the Client; a model never selects these values. */\nexport interface BrowserOptions extends AutomationOptions {\n readonly launch: LaunchRecipe;\n /** Required whenever the launch recipe persists a context. */\n readonly contextWriter?: ContextWriterPermit;\n readonly onCleanup?: (result: CleanupResult) => Effect.Effect<void>;\n readonly onAllocationUncertain?: (attempt: AllocationAttempt) => Effect.Effect<void>;\n}\n\nexport interface Handoff {\n readonly token: Redacted.Redacted<string>;\n readonly view: LiveView;\n}\n\n/** Browserbase identity, remote artifacts and provider cleanup remain hosted capabilities. */\nexport interface BrowserbaseSession<E = never> extends BrowserSession<E> {\n readonly reference: SessionReference;\n readonly closeChecked: Effect.Effect<CleanupResult, BrowserError>;\n readonly clickForDownload: (\n request: ClickRequest,\n ) => Effect.Effect<DownloadObservation, BrowserError>;\n /** Attaches to an existing file input; an uploaded branch needs a receipt for this session. */\n readonly selectFiles: (request: SelectFilesRequest) => Effect.Effect<ActionResult, BrowserError>;\n /** Registers the chooser observation before the single click that opens it. */\n readonly clickForFileSelection: (\n request: SelectFilesRequest,\n ) => Effect.Effect<ActionResult, BrowserError>;\n readonly liveView: (expiresInSeconds?: number) => Effect.Effect<LiveView, BrowserError>;\n readonly beginHandoff: (expiresInSeconds?: number) => Effect.Effect<Handoff, BrowserError>;\n readonly resume: (\n token: Redacted.Redacted<string>,\n operatorReleasedControl: boolean,\n ) => Effect.Effect<Observation, BrowserError>;\n readonly detach: Effect.Effect<\n { readonly reference: SessionReference; readonly targetId: string },\n BrowserError\n >;\n readonly reconnect: (\n operatorReleasedControl: boolean,\n ) => Effect.Effect<Observation, BrowserError | InitializationError>;\n readonly close: Effect.Effect<CleanupResult>;\n readonly cleanupResult: Effect.Effect<Option.Option<CleanupResult>>;\n}\n\nexport interface AttachRequest<E = never, R = never> extends OpenOptions<E, R> {\n readonly policy: BrowserPolicy;\n /** The exact page to resume; without it the session must have exactly one page. */\n readonly target?: { readonly targetId: string };\n /** Bounded admission of a session the provider has not finished starting. */\n readonly pendingWaitMillis?: number;\n}\n\nexport interface BrowserAcquisition<E = never> {\n readonly reference: SessionReference;\n readonly attempt: AllocationAttempt;\n readonly failure: Effect.Effect<never, E | InitializationError>;\n readonly connect: Effect.Effect<BrowserbaseSession<E>, BrowserError | E | InitializationError>;\n readonly close: Effect.Effect<CleanupResult>;\n}\n\n/** Only receipts issued for this exact provider session may resolve to stored paths. */\nconst selection = (\n request: SelectFilesRequest,\n reference: SessionReference,\n operation: BrowserOperation,\n): Effect.Effect<BrowserRuntime.ResolvedFileSelection, BrowserError> =>\n Effect.suspend(() => {\n if (request.selection._tag === \"Inline\")\n return Effect.succeed<BrowserRuntime.ResolvedFileSelection>({\n _tag: \"Inline\",\n files: request.selection.files,\n });\n\n const uploads = request.selection.uploads;\n\n if (!isList(uploads) || uploads.length < 1 || uploads.length > 8)\n return Effect.fail(\n BrowserError.make({\n operation,\n reason: Reasons.Configuration.make({}),\n outcome: \"undispatched\",\n }),\n );\n const paths: string[] = [];\n\n for (const receipt of uploads) {\n const issued = issuedUpload(receipt);\n\n if (\n issued === undefined ||\n issued.reference.projectId !== reference.projectId ||\n issued.reference.sessionId !== reference.sessionId\n )\n return Effect.fail(\n BrowserError.make({\n operation,\n reason: Reasons.Authorization.make({}),\n outcome: \"undispatched\",\n }),\n );\n paths.push(issued.remotePath);\n }\n\n return Effect.succeed<BrowserRuntime.ResolvedFileSelection>({ _tag: \"Stored\", paths });\n });\n\nconst makeSession = <E>(\n connection: BrowserRuntime.Connection<SessionReference, E>,\n lifetime: RemoteLease,\n): BrowserbaseSession<E> => {\n const { session, operations } = connection;\n\n // Decorating the same object preserves its private capture and page-control associations.\n return Object.assign(session, {\n reference: lifetime.reference,\n closeChecked: session.closeChecked.pipe(Effect.andThen(lifetime.closeChecked)),\n clickForDownload: (request) =>\n operations.clickForDownload(request).pipe(\n Effect.flatMap((event) =>\n Schema.decodeEffect(DownloadObservation)({\n ...event,\n reference: lifetime.reference,\n }).pipe(\n Effect.mapError(() =>\n BrowserError.make({\n operation: \"download-action\",\n reason: Reasons.Malformed.make({}),\n outcome: \"unknown\",\n }),\n ),\n ),\n ),\n ),\n selectFiles: (request) =>\n selection(request, lifetime.reference, \"select-files\").pipe(\n Effect.flatMap((files) =>\n operations.selectFiles({ selector: request.selector, selection: files }),\n ),\n ),\n clickForFileSelection: (request) =>\n selection(request, lifetime.reference, \"file-chooser\").pipe(\n Effect.flatMap((files) =>\n operations.clickForFileSelection({ selector: request.selector, selection: files }),\n ),\n ),\n liveView: (ttl = 60) => operations.liveView(lifetime.liveView(ttl)),\n beginHandoff: (ttl = 60) => operations.beginHandoff(lifetime.liveView(ttl)),\n resume: operations.resume,\n detach: operations.detach,\n reconnect: operations.reconnect,\n close: lifetime.release,\n cleanupResult: lifetime.cleanupResult,\n } satisfies Omit<BrowserbaseSession<E>, Exclude<keyof BrowserSession<E>, \"closeChecked\">>);\n};\n\nexport class BrowserbaseBrowser extends Context.Service<\n BrowserbaseBrowser,\n {\n readonly acquire: <E = never, R = never>(\n policy: BrowserPolicy,\n request?: OpenOptions<E, R>,\n ) => Effect.Effect<\n BrowserAcquisition<E>,\n AllocationError | BrowserError | ContextError,\n Scope.Scope | Exclude<R, Scope.Scope>\n >;\n /** Borrowed control of a session this process did not allocate and will not release. */\n readonly attach: <E = never, R = never>(\n reference: SessionReference,\n request: AttachRequest<E, R>,\n ) => Effect.Effect<\n BrowserbaseSession<E>,\n BrowserError | SessionError | E | InitializationError,\n Scope.Scope | Exclude<R, Scope.Scope>\n >;\n readonly open: <E = never, R = never>(\n policy: BrowserPolicy,\n request?: OpenOptions<E, R>,\n ) => Effect.Effect<\n BrowserbaseSession<E>,\n AllocationError | BrowserError | ContextError | E | InitializationError,\n Scope.Scope | Exclude<R, Scope.Scope>\n >;\n }\n>()(\"effect-browserbase/Browser\") {\n /** Open through the configured account and browser service, in the caller's scope. */\n static open<E = never, R = never>(policy: BrowserPolicy, request?: OpenOptions<E, R>) {\n return Effect.flatMap(BrowserbaseBrowser, (browser) => browser.open(policy, request));\n }\n\n /** Allocate the provider lifetime before connecting, preserving its attempt and cleanup. */\n static acquire<E = never, R = never>(policy: BrowserPolicy, request?: OpenOptions<E, R>) {\n return Effect.flatMap(BrowserbaseBrowser, (browser) => browser.acquire(policy, request));\n }\n\n /** Borrow a provider session without acquiring release authority over it. */\n static attach<E = never, R = never>(reference: SessionReference, request: AttachRequest<E, R>) {\n return Effect.flatMap(BrowserbaseBrowser, (browser) => browser.attach(reference, request));\n }\n\n /** Allocation attempts, connection ids and handoff tokens come from the required `Crypto`. */\n static layer(\n options: BrowserOptions,\n ): Layer.Layer<\n BrowserbaseBrowser,\n BrowserError,\n BrowserbaseClient | BrowserbaseSessions | Crypto.Crypto\n > {\n return Layer.effect(\n BrowserbaseBrowser,\n Effect.gen(function* () {\n const client = yield* BrowserbaseClient;\n const sessions = yield* BrowserbaseSessions;\n const crypto = yield* Crypto.Crypto;\n const binding = yield* BrowserbaseBrowserBinding;\n\n if (options.launch.context?.persist === true && options.contextWriter === undefined)\n return yield* BrowserError.make({\n operation: \"configure\",\n reason: Reasons.ContextLease.make({}),\n outcome: \"undispatched\",\n });\n if (Object.prototype.hasOwnProperty.call(options, \"bootstrap\"))\n return yield* BrowserError.make({\n operation: \"configure\",\n reason: Reasons.Configuration.make({}),\n outcome: \"undispatched\",\n });\n\n const runtime = yield* BrowserRuntime.make({\n implementation: \"browserbase-playwright-cdp\",\n binding,\n automation: projected(options),\n viewport:\n options.launch.viewport._tag === \"Fixed\"\n ? { width: options.launch.viewport.width, height: options.launch.viewport.height }\n : { width: 1280, height: 720 },\n preserveViewport: options.launch.viewport._tag !== \"Fixed\",\n keepAlive: options.launch.keepAlive === true,\n });\n\n const source =\n <L extends BrowserRuntime.Lifetime, E>(\n remote: BrowserRuntime.Source<\n L,\n E,\n BrowserbaseClient | BrowserbaseSessions | Crypto.Crypto\n >,\n ): BrowserRuntime.Source<L, E> =>\n (cleanup, deadline) =>\n remote(cleanup, deadline).pipe(\n Effect.provideService(BrowserbaseClient, client),\n Effect.provideService(BrowserbaseSessions, sessions),\n Effect.provideService(Crypto.Crypto, crypto),\n );\n\n const acquire = Effect.fnUntraced(function* <E = never, R = never>(\n policy: BrowserPolicy,\n request: OpenOptions<E, R> = {},\n ) {\n const acquired = yield* runtime.acquire(\n policy,\n source(\n ownedRemote({\n launch: options.launch,\n ...(options.contextWriter === undefined\n ? {}\n : { contextWriter: options.contextWriter }),\n ...(options.onCleanup === undefined ? {} : { onCleanup: options.onCleanup }),\n ...(options.onAllocationUncertain === undefined\n ? {}\n : { onAllocationUncertain: options.onAllocationUncertain }),\n }),\n ),\n request,\n );\n\n const connected = yield* Effect.cached(\n acquired.connect.pipe(\n Effect.map((connection) => makeSession(connection, acquired.lifetime)),\n ),\n );\n\n return {\n reference: acquired.reference,\n attempt: acquired.lifetime.attempt,\n failure: acquired.failure,\n close: acquired.close,\n connect: acquired.connect.pipe(Effect.andThen(connected)),\n } satisfies BrowserAcquisition<E>;\n });\n\n const attach = Effect.fnUntraced(function* <E = never, R = never>(\n reference: SessionReference,\n request: AttachRequest<E, R>,\n ) {\n const acquired = yield* runtime.acquire(\n request.policy,\n source(\n borrowedRemote({\n reference,\n ...(request.pendingWaitMillis === undefined\n ? {}\n : { pendingWaitMillis: request.pendingWaitMillis }),\n ...(options.onCleanup === undefined ? {} : { onCleanup: options.onCleanup }),\n }),\n ),\n {\n ...(request.bootstrap === undefined ? {} : { bootstrap: request.bootstrap }),\n existingTarget: request.target ?? {},\n },\n );\n\n return yield* acquired.connect.pipe(\n Effect.map((connection) => makeSession(connection, acquired.lifetime)),\n );\n });\n\n return BrowserbaseBrowser.of({\n acquire,\n attach,\n open: (policy, request) =>\n acquire(policy, request).pipe(Effect.flatMap((acquired) => acquired.connect)),\n });\n }),\n );\n }\n}\n\n/** Only the automation fields cross the schema boundary; launch and callbacks are separate. */\nconst projected = (options: BrowserOptions) => ({\n ...(options.maxHostReads === undefined ? {} : { maxHostReads: options.maxHostReads }),\n ...(options.actionTimeoutMillis === undefined\n ? {}\n : { actionTimeoutMillis: options.actionTimeoutMillis }),\n ...(options.maxPages === undefined ? {} : { maxPages: options.maxPages }),\n ...(options.initialPage === undefined ? {} : { initialPage: options.initialPage }),\n ...(options.popupPolicy === undefined ? {} : { popupPolicy: options.popupPolicy }),\n ...(options.dialogPolicy === undefined ? {} : { dialogPolicy: options.dialogPolicy }),\n ...(options.pageControl === undefined ? {} : { pageControl: options.pageControl }),\n});\n"],"mappings":";;;;;;;;;;;;;;AAyBA,MAAM,WAAW,WACf,aAAa,KAAK;CAAE,WAAW;CAAkB;CAAQ,SAAS;AAAe,CAAC;;;;;;AAOpF,MAAa,eAAe,OAAO,WAAW,WAC5C,SACA,QAAsB,mBACtB,QACA;CACA,MAAM,SAAS,OAAO;CACtB,MAAM,WAAW,OAAO;CACxB,MAAM,SAAS,OAAO,MAAM;CAC5B,MAAM,oBAAoB,QAAQ,qBAAqB;CAEvD,IACE,CAAC,OAAO,cAAc,iBAAiB,KACvC,oBAAoB,KACpB,oBAAoB,KAEpB,OAAO,OAAO,QAAQ,eAAe;CAIvC,MAAM,WAAW,OAAO,SAAS,SAAS,QAAQ,SAAS;CAE3D,IAAI,wBAAwB,SAAS,MAAM,GAAG,OAAO,OAAO,QAAQ,SAAS;CAC7E,IAAI,SAAS,WAAW,WAAW;EACjC,IAAI,sBAAsB,GAAG,OAAO,OAAO,QAAQ,QAAQ;EAC3D,OAAO,SAAS,iBAAiB,SAAS,WAAW,EAAE,eAAe,kBAAkB,CAAC;CAC3F;CACA,MAAM,YAAY,SAAS;CAE3B,OAAO,OAAO,OAAO,gBACnB,OAAO,IAAI,aAAa;EACtB,MAAM,gBAAgB,OAAO,MAAM,KAAK;EACxC,IAAI,UAAU;EACd,IAAI;EAEJ,MAAM,YAAY,OAAO,OAAO,OAC9B,OAAO,gBACL,OAAO,IAAI,aAAa;GACtB,UAAU;GAaV,QAAO,OAXoB,YACzB,WACA,YACA,UACA,QACC,WAAW;IACV,UAAU;GACZ,GACA,MACF,EAAA,CAEmB;GACnB,MAAM,SAAS;GACf,MAAM,SAAS,QAAQ;GAEvB,IAAI,WAAW,KAAA,GAAW;IACxB,OAAO,SAAS,OAAO,cAAc,cAAc,MAAM,CAAC,CAAC;IAC3D,IAAI,WAAW,KAAA,GAAW,OAAO,SAAS,OAAO,cAAc,OAAO,MAAM,CAAC,CAAC;GAChF;EACF,CAAC,CACH,CACF;EAEA,MAAM,aAAa,OAAO,OAAO,OAAO,MAAM,MAAM,eAAe,KAAK,IAAI,CAAC;EAG7E,OAAO,MAAM,aAAa,eAAe,SAAS;EAClD,OAAO,MAAM,aAAa,QAAQ,UAAU;EAE5C,OAAO;GACL;GACA,QAAQ;GACR,aAAa,kBACX,OAAO,cACL,UACI,OAAO,KACL,aAAa,KAAK;IAChB,WAAW;IACX,QAAQ;IACR,SAAS;GACX,CAAC,CACH,IAEA,kBAAkB,QAAQ,UAAU,WAAW,aAAa,CAClE;GACF,SAAS,WAAW,KAClB,OAAO,QACL,OAAO,cACL,YAAY,KAAA,IACR,OAAO,oBAAI,IAAI,MAAM,kDAAkD,CAAC,IACxE,OAAO,QAAQ,OAAO,CAC5B,CACF,CACF;GACA,eAAe,OAAO,WAAW,OAAO,cAAc,OAAO,CAAC;EAChE;CACF,CAAC,CACH;AACF,CAAC;;;;AClGD,MAAM,kBACJ,UAEA,MAAM,KACJ,OAAO,cACJ,WACC,OAAO,UAAU,YACjB,OAAO,OAAO,WAAW,MACxB,OAAO,cAAc,aAClB,OAAO,WAAW,cAClB,OAAO,WAAW,oBAEtB,aAAa,KAAK;CAChB,WAAW;CACX,QAAQ,QAAQ,SAAS,KAAK,CAAC,CAAC;CAChC,SAAS;AACX,CAAC,CACL,CACF;AAEF,MAAM,kBAUJ,cACI;CACJ,GAAG;CACH,aAAa,kBACX,SACG,WAAW,aAAa,CAAC,CACzB,KAAK,OAAO,UAAU,UAAU,sBAAsB,WAAW,KAAK,CAAC,CAAC;CAC7E,cAAc,eAAe,SAAS,OAAO;CAC7C,gBAAgB,SAAS,cAAc,KACrC,OAAO,KACJ,WACC,OAAO,OAAO,MAAM,KACpB,OAAO,MAAM,cAAc,WAC3B,OAAO,MAAM,WAAW,WAC5B,CACF;AACF;;AAgBA,MAAM,oBACJ,QACA,UACA,eACI;CACJ,WAAW,QAAgB,cAAc,QAAQ,WAAW,GAAG;CAC/D,iBAAiB,SAAS,SAAS,SAAS,CAAC,CAAC,KAC5C,OAAO,UAAU,UAAU,sBAAsB,aAAa,KAAK,CAAC,GACpE,OAAO,SAAS,WACd,OAAO,WAAW,YACd,OAAO,OACP,OAAO,KACL,aAAa,KAAK;EAChB,WAAW;EACX,QAAQ,QAAQ,QAAQ,KAAK,CAAC,CAAC;EAC/B,SAAS;CACX,CAAC,CACH,CACN,CACF;AACF;AAEA,MAAa,eAET,aAED,OAAO,qBACN,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO;CACtB,MAAM,WAAW,OAAO;CAExB,MAAM,WAAW,OAAO,cACtB;EACE,QAAQ,QAAQ;EAChB,GAAI,QAAQ,kBAAkB,KAAA,IAAY,CAAC,IAAI,EAAE,eAAe,QAAQ,cAAc;EACtF,oBAAoB;EACpB,GAAI,QAAQ,cAAc,KAAA,IAAY,CAAC,IAAI,EAAE,WAAW,QAAQ,UAAU;EAC1E,GAAI,QAAQ,0BAA0B,KAAA,IAClC,CAAC,IACD,EAAE,uBAAuB,QAAQ,sBAAsB;CAC7D,GACA,KACF;CAEA,OAAO;EACL,GAAG,eAAe,QAAQ;EAC1B,GAAG,iBAAiB,QAAQ,UAAU,SAAS,SAAS;CAC1D;AACF,CAAC;;AAGL,MAAa,kBACV,aAKA,UACC,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO;CACtB,MAAM,WAAW,OAAO;CACxB,MAAM,WAAW,OAAO,aAAa,SAAS,KAAK;CAEnD,OAAO;EACL,GAAG,eAAe,QAAQ;EAC1B,GAAG,iBAAiB,QAAQ,UAAU,SAAS,SAAS;CAC1D;AACF,CAAC;;;;ACzDL,MAAM,aACJ,SACA,WACA,cAEA,OAAO,cAAc;CACnB,IAAI,QAAQ,UAAU,SAAS,UAC7B,OAAO,OAAO,QAA8C;EAC1D,MAAM;EACN,OAAO,QAAQ,UAAU;CAC3B,CAAC;CAEH,MAAM,UAAU,QAAQ,UAAU;CAElC,IAAI,CAAC,OAAO,OAAO,KAAK,QAAQ,SAAS,KAAK,QAAQ,SAAS,GAC7D,OAAO,OAAO,KACZ,aAAa,KAAK;EAChB;EACA,QAAQ,QAAQ,cAAc,KAAK,CAAC,CAAC;EACrC,SAAS;CACX,CAAC,CACH;CACF,MAAM,QAAkB,CAAC;CAEzB,KAAK,MAAM,WAAW,SAAS;EAC7B,MAAM,SAAS,aAAa,OAAO;EAEnC,IACE,WAAW,KAAA,KACX,OAAO,UAAU,cAAc,UAAU,aACzC,OAAO,UAAU,cAAc,UAAU,WAEzC,OAAO,OAAO,KACZ,aAAa,KAAK;GAChB;GACA,QAAQ,QAAQ,cAAc,KAAK,CAAC,CAAC;GACrC,SAAS;EACX,CAAC,CACH;EACF,MAAM,KAAK,OAAO,UAAU;CAC9B;CAEA,OAAO,OAAO,QAA8C;EAAE,MAAM;EAAU;CAAM,CAAC;AACvF,CAAC;AAEH,MAAM,eACJ,YACA,aAC0B;CAC1B,MAAM,EAAE,SAAS,eAAe;CAGhC,OAAO,OAAO,OAAO,SAAS;EAC5B,WAAW,SAAS;EACpB,cAAc,QAAQ,aAAa,KAAK,OAAO,QAAQ,SAAS,YAAY,CAAC;EAC7E,mBAAmB,YACjB,WAAW,iBAAiB,OAAO,CAAC,CAAC,KACnC,OAAO,SAAS,UACd,OAAO,aAAa,mBAAmB,CAAC,CAAC;GACvC,GAAG;GACH,WAAW,SAAS;EACtB,CAAC,CAAC,CAAC,KACD,OAAO,eACL,aAAa,KAAK;GAChB,WAAW;GACX,QAAQ,QAAQ,UAAU,KAAK,CAAC,CAAC;GACjC,SAAS;EACX,CAAC,CACH,CACF,CACF,CACF;EACF,cAAc,YACZ,UAAU,SAAS,SAAS,WAAW,cAAc,CAAC,CAAC,KACrD,OAAO,SAAS,UACd,WAAW,YAAY;GAAE,UAAU,QAAQ;GAAU,WAAW;EAAM,CAAC,CACzE,CACF;EACF,wBAAwB,YACtB,UAAU,SAAS,SAAS,WAAW,cAAc,CAAC,CAAC,KACrD,OAAO,SAAS,UACd,WAAW,sBAAsB;GAAE,UAAU,QAAQ;GAAU,WAAW;EAAM,CAAC,CACnF,CACF;EACF,WAAW,MAAM,OAAO,WAAW,SAAS,SAAS,SAAS,GAAG,CAAC;EAClE,eAAe,MAAM,OAAO,WAAW,aAAa,SAAS,SAAS,GAAG,CAAC;EAC1E,QAAQ,WAAW;EACnB,QAAQ,WAAW;EACnB,WAAW,WAAW;EACtB,OAAO,SAAS;EAChB,eAAe,SAAS;CAC1B,CAAyF;AAC3F;AAEA,IAAa,qBAAb,MAAa,2BAA2B,QAAQ,QA6B9C,CAAC,CAAC,4BAA4B,CAAC,CAAC;;CAEhC,OAAO,KAA2B,QAAuB,SAA6B;EACpF,OAAO,OAAO,QAAQ,qBAAqB,YAAY,QAAQ,KAAK,QAAQ,OAAO,CAAC;CACtF;;CAGA,OAAO,QAA8B,QAAuB,SAA6B;EACvF,OAAO,OAAO,QAAQ,qBAAqB,YAAY,QAAQ,QAAQ,QAAQ,OAAO,CAAC;CACzF;;CAGA,OAAO,OAA6B,WAA6B,SAA8B;EAC7F,OAAO,OAAO,QAAQ,qBAAqB,YAAY,QAAQ,OAAO,WAAW,OAAO,CAAC;CAC3F;;CAGA,OAAO,MACL,SAKA;EACA,OAAO,MAAM,OACX,oBACA,OAAO,IAAI,aAAa;GACtB,MAAM,SAAS,OAAO;GACtB,MAAM,WAAW,OAAO;GACxB,MAAM,SAAS,OAAO,OAAO;GAC7B,MAAM,UAAU,OAAO;GAEvB,IAAI,QAAQ,OAAO,SAAS,YAAY,QAAQ,QAAQ,kBAAkB,KAAA,GACxE,OAAO,OAAO,aAAa,KAAK;IAC9B,WAAW;IACX,QAAQ,QAAQ,aAAa,KAAK,CAAC,CAAC;IACpC,SAAS;GACX,CAAC;GACH,IAAI,OAAO,UAAU,eAAe,KAAK,SAAS,WAAW,GAC3D,OAAO,OAAO,aAAa,KAAK;IAC9B,WAAW;IACX,QAAQ,QAAQ,cAAc,KAAK,CAAC,CAAC;IACrC,SAAS;GACX,CAAC;GAEH,MAAM,UAAU,OAAO,eAAe,KAAK;IACzC,gBAAgB;IAChB;IACA,YAAY,UAAU,OAAO;IAC7B,UACE,QAAQ,OAAO,SAAS,SAAS,UAC7B;KAAE,OAAO,QAAQ,OAAO,SAAS;KAAO,QAAQ,QAAQ,OAAO,SAAS;IAAO,IAC/E;KAAE,OAAO;KAAM,QAAQ;IAAI;IACjC,kBAAkB,QAAQ,OAAO,SAAS,SAAS;IACnD,WAAW,QAAQ,OAAO,cAAc;GAC1C,CAAC;GAED,MAAM,UAEF,YAMD,SAAS,aACR,OAAO,SAAS,QAAQ,CAAC,CAAC,KACxB,OAAO,eAAe,mBAAmB,MAAM,GAC/C,OAAO,eAAe,qBAAqB,QAAQ,GACnD,OAAO,eAAe,OAAO,QAAQ,MAAM,CAC7C;GAEJ,MAAM,UAAU,OAAO,WAAW,WAChC,QACA,UAA6B,CAAC,GAC9B;IACA,MAAM,WAAW,OAAO,QAAQ,QAC9B,QACA,OACE,YAAY;KACV,QAAQ,QAAQ;KAChB,GAAI,QAAQ,kBAAkB,KAAA,IAC1B,CAAC,IACD,EAAE,eAAe,QAAQ,cAAc;KAC3C,GAAI,QAAQ,cAAc,KAAA,IAAY,CAAC,IAAI,EAAE,WAAW,QAAQ,UAAU;KAC1E,GAAI,QAAQ,0BAA0B,KAAA,IAClC,CAAC,IACD,EAAE,uBAAuB,QAAQ,sBAAsB;IAC7D,CAAC,CACH,GACA,OACF;IAEA,MAAM,YAAY,OAAO,OAAO,OAC9B,SAAS,QAAQ,KACf,OAAO,KAAK,eAAe,YAAY,YAAY,SAAS,QAAQ,CAAC,CACvE,CACF;IAEA,OAAO;KACL,WAAW,SAAS;KACpB,SAAS,SAAS,SAAS;KAC3B,SAAS,SAAS;KAClB,OAAO,SAAS;KAChB,SAAS,SAAS,QAAQ,KAAK,OAAO,QAAQ,SAAS,CAAC;IAC1D;GACF,CAAC;GAED,MAAM,SAAS,OAAO,WAAW,WAC/B,WACA,SACA;IACA,MAAM,WAAW,OAAO,QAAQ,QAC9B,QAAQ,QACR,OACE,eAAe;KACb;KACA,GAAI,QAAQ,sBAAsB,KAAA,IAC9B,CAAC,IACD,EAAE,mBAAmB,QAAQ,kBAAkB;KACnD,GAAI,QAAQ,cAAc,KAAA,IAAY,CAAC,IAAI,EAAE,WAAW,QAAQ,UAAU;IAC5E,CAAC,CACH,GACA;KACE,GAAI,QAAQ,cAAc,KAAA,IAAY,CAAC,IAAI,EAAE,WAAW,QAAQ,UAAU;KAC1E,gBAAgB,QAAQ,UAAU,CAAC;IACrC,CACF;IAEA,OAAO,OAAO,SAAS,QAAQ,KAC7B,OAAO,KAAK,eAAe,YAAY,YAAY,SAAS,QAAQ,CAAC,CACvE;GACF,CAAC;GAED,OAAO,mBAAmB,GAAG;IAC3B;IACA;IACA,OAAO,QAAQ,YACb,QAAQ,QAAQ,OAAO,CAAC,CAAC,KAAK,OAAO,SAAS,aAAa,SAAS,OAAO,CAAC;GAChF,CAAC;EACH,CAAC,CACH;CACF;AACF;;AAGA,MAAM,aAAa,aAA6B;CAC9C,GAAI,QAAQ,iBAAiB,KAAA,IAAY,CAAC,IAAI,EAAE,cAAc,QAAQ,aAAa;CACnF,GAAI,QAAQ,wBAAwB,KAAA,IAChC,CAAC,IACD,EAAE,qBAAqB,QAAQ,oBAAoB;CACvD,GAAI,QAAQ,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,QAAQ,SAAS;CACvE,GAAI,QAAQ,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa,QAAQ,YAAY;CAChF,GAAI,QAAQ,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa,QAAQ,YAAY;CAChF,GAAI,QAAQ,iBAAiB,KAAA,IAAY,CAAC,IAAI,EAAE,cAAc,QAAQ,aAAa;CACnF,GAAI,QAAQ,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa,QAAQ,YAAY;AAClF"}
1
+ {"version":3,"file":"Browser-BPcF550A.mjs","names":[],"sources":["../src/internal/session/Attachment.ts","../src/internal/session/Browser.ts","../src/Browser.ts"],"sourcesContent":["import { Effect, Exit, Option, Scope } from \"effect\";\n\nimport type { CleanupResult } from \"../../Cleanup.ts\";\nimport { BrowserbaseClient } from \"../../Client.ts\";\nimport { SessionError } from \"../../Errors.ts\";\nimport type { SessionReference } from \"../../References.ts\";\nimport { isTerminalSessionStatus } from \"../../SessionData.ts\";\nimport { BrowserbaseSessions } from \"../../Sessions.ts\";\nimport { connectionAddress } from \"../provider/Connection.ts\";\nimport {\n makeCleanup,\n noLocalConnection,\n reported,\n type CleanupLimits,\n type LocalCleanup,\n} from \"./Cleanup.ts\";\nimport { reportCleanup } from \"./Diagnostics.ts\";\n\nexport interface AttachmentOptions {\n readonly reference: SessionReference;\n /** Bounded admission of a session the provider has not finished starting. */\n readonly pendingWaitMillis?: number;\n readonly onCleanup?: (result: CleanupResult) => Effect.Effect<void>;\n}\n\nconst failure = (reason: SessionError[\"reason\"]) =>\n SessionError.make({ operation: \"session-attach\", reason, outcome: \"undispatched\" });\n\n/**\n * Borrowing an already running session. This scope owns its local connection and nothing\n * else: no allocation attempt is made, no release is requested, and no Context-writer\n * authority is claimed. Whoever allocated the session keeps all three.\n */\nexport const attachRemote = Effect.fnUntraced(function* (\n options: AttachmentOptions,\n local: LocalCleanup = noLocalConnection,\n limits?: CleanupLimits,\n) {\n const client = yield* BrowserbaseClient;\n const sessions = yield* BrowserbaseSessions;\n const parent = yield* Scope.Scope;\n const pendingWaitMillis = options.pendingWaitMillis ?? 0;\n\n if (\n !Number.isSafeInteger(pendingWaitMillis) ||\n pendingWaitMillis < 0 ||\n pendingWaitMillis > 600_000\n )\n return yield* failure(\"configuration\");\n\n // The status read validates project authority before anything is borrowed. A terminal\n // session needs a fresh allocation from durable state, never a reattachment.\n const observed = yield* sessions.retrieve(options.reference);\n\n if (isTerminalSessionStatus(observed.status)) return yield* failure(\"expired\");\n if (observed.status !== \"RUNNING\") {\n if (pendingWaitMillis === 0) return yield* failure(\"active\");\n yield* sessions.waitUntilRunning(observed.reference, { timeoutMillis: pendingWaitMillis });\n }\n const reference = observed.reference;\n\n return yield* Effect.uninterruptible(\n Effect.gen(function* () {\n const resourceScope = yield* Scope.make();\n let closing = false;\n let cleanup: CleanupResult | undefined;\n\n const terminate = yield* Effect.cached(\n Effect.uninterruptible(\n Effect.gen(function* () {\n closing = true;\n\n const coordinator = yield* makeCleanup(\n reference,\n \"borrowed\",\n sessions,\n local,\n (result) => {\n cleanup = result;\n },\n limits,\n );\n\n yield* coordinator.close;\n const result = cleanup;\n const notify = options.onCleanup;\n\n if (result !== undefined) {\n yield* reported(Effect.suspend(() => reportCleanup(result)));\n if (notify !== undefined) yield* reported(Effect.suspend(() => notify(result)));\n }\n }),\n ),\n );\n\n const closeScope = yield* Effect.cached(Scope.close(resourceScope, Exit.void));\n\n // Teardown is registered before the first connection, exactly as an owned scope does.\n yield* Scope.addFinalizer(resourceScope, terminate);\n yield* Scope.addFinalizer(parent, closeScope);\n\n return {\n reference,\n status: observed,\n connection: (timeoutMillis: number) =>\n Effect.suspend(() =>\n closing\n ? Effect.fail(\n SessionError.make({\n operation: \"session-connect\",\n reason: \"expired\",\n outcome: \"undispatched\",\n }),\n )\n : // Credentials are fetched fresh: an expiry can race the caller's own read.\n connectionAddress(client, sessions, reference, timeoutMillis),\n ),\n release: closeScope.pipe(\n Effect.andThen(\n Effect.suspend(() =>\n cleanup === undefined\n ? Effect.die(new Error(\"Borrowed session closed without cleanup evidence\"))\n : Effect.succeed(cleanup),\n ),\n ),\n ),\n cleanupResult: Effect.sync(() => Option.fromNullishOr(cleanup)),\n };\n }),\n );\n});\n","import { type Crypto, Effect, Option, type Redacted } from \"effect\";\nimport type { Lifetime, Source } from \"effect-browser/browser-runtime\";\nimport { BrowserError, Reasons } from \"effect-browser/errors\";\n\nimport type { CleanupResult } from \"../../Cleanup.ts\";\nimport { BrowserbaseClient } from \"../../Client.ts\";\nimport type { AllocationError, ContextError, SessionError } from \"../../Errors.ts\";\nimport type { LaunchRecipe } from \"../../Launch.ts\";\nimport type { AllocationAttempt, SessionReference } from \"../../References.ts\";\nimport { BrowserbaseSessions } from \"../../Sessions.ts\";\nimport { issueLiveView, type LiveView } from \"../browser/LiveView.ts\";\nimport { browserRequestFailure } from \"../browser/RequestFailure.ts\";\nimport { acquireRemote } from \"./Acquisition.ts\";\nimport { attachRemote } from \"./Attachment.ts\";\nimport type { ContextWriterPermit } from \"./WriterFacts.ts\";\n\nexport interface RemoteLease extends Lifetime {\n readonly reference: SessionReference;\n readonly closeChecked: Effect.Effect<CleanupResult, BrowserError>;\n readonly attempt?: AllocationAttempt;\n readonly release: Effect.Effect<CleanupResult>;\n readonly cleanupResult: Effect.Effect<Option.Option<CleanupResult>>;\n readonly liveView: (ttl: number) => Effect.Effect<LiveView, BrowserError>;\n}\n\ntype RemoteSource<L extends Lifetime, E> = Source<\n L,\n E,\n BrowserbaseClient | BrowserbaseSessions | Crypto.Crypto\n>;\n\n/** A borrowed connection closes without requiring or requesting remote termination. */\nconst checkedCleanup = (\n close: Effect.Effect<CleanupResult>,\n): Effect.Effect<CleanupResult, BrowserError> =>\n close.pipe(\n Effect.filterOrFail(\n (result) =>\n result.local === \"closed\" &&\n result.issues.length === 0 &&\n (result.ownership === \"borrowed\"\n ? result.remote === \"not-owned\"\n : result.remote === \"confirmed\"),\n () =>\n BrowserError.make({\n operation: \"close\",\n reason: Reasons.Provider.make({}),\n outcome: \"unknown\",\n }),\n ),\n );\n\nconst withConnection = <\n A extends {\n readonly reference: SessionReference;\n readonly connection: (\n timeoutMillis: number,\n ) => Effect.Effect<Redacted.Redacted<string>, SessionError>;\n readonly release: Effect.Effect<CleanupResult>;\n readonly cleanupResult: Effect.Effect<Option.Option<CleanupResult>>;\n },\n>(\n acquired: A,\n) => ({\n ...acquired,\n connection: (timeoutMillis: number) =>\n acquired\n .connection(timeoutMillis)\n .pipe(Effect.mapError((error) => browserRequestFailure(\"connect\", error))),\n closeChecked: checkedCleanup(acquired.release),\n controlRetired: acquired.cleanupResult.pipe(\n Effect.map(\n (result) =>\n Option.isSome(result) &&\n result.value.ownership === \"owned\" &&\n result.value.remote === \"confirmed\",\n ),\n ),\n});\n\nexport interface OwnedLease extends RemoteLease {\n readonly attempt: AllocationAttempt;\n}\n\nexport interface OwnedOptions {\n /** The single provider-faithful launch description; the owner adds no second default body. */\n readonly launch: LaunchRecipe;\n /** Required for a persistent context; the writer permit, not this owner, holds that authority. */\n readonly contextWriter?: ContextWriterPermit;\n readonly onCleanup?: (result: CleanupResult) => Effect.Effect<void>;\n readonly onAllocationUncertain?: (attempt: AllocationAttempt) => Effect.Effect<void>;\n}\n\n/** Allocates the session, and therefore owns releasing it. */\nconst providerControls = (\n client: BrowserbaseClient[\"Service\"],\n sessions: BrowserbaseSessions[\"Service\"],\n reference: SessionReference,\n) => ({\n liveView: (ttl: number) => issueLiveView(client, reference, ttl),\n verifyReconnect: sessions.retrieve(reference).pipe(\n Effect.mapError((error) => browserRequestFailure(\"reconnect\", error)),\n Effect.flatMap((status) =>\n status.status === \"RUNNING\"\n ? Effect.void\n : Effect.fail(\n BrowserError.make({\n operation: \"reconnect\",\n reason: Reasons.Expired.make({}),\n outcome: \"undispatched\",\n }),\n ),\n ),\n ),\n});\n\nexport const ownedRemote =\n (\n options: OwnedOptions,\n ): RemoteSource<OwnedLease, AllocationError | BrowserError | ContextError> =>\n (local, lifetimeDeadline) =>\n Effect.gen(function* () {\n const client = yield* BrowserbaseClient;\n const sessions = yield* BrowserbaseSessions;\n\n const acquired = yield* acquireRemote(\n {\n launch: options.launch,\n ...(options.contextWriter === undefined ? {} : { contextWriter: options.contextWriter }),\n allocationDeadline: lifetimeDeadline,\n ...(options.onCleanup === undefined ? {} : { onCleanup: options.onCleanup }),\n ...(options.onAllocationUncertain === undefined\n ? {}\n : { onAllocationUncertain: options.onAllocationUncertain }),\n },\n local,\n );\n\n return {\n ...withConnection(acquired),\n ...providerControls(client, sessions, acquired.reference),\n };\n });\n\n/** Borrows a running session: local connection only, and never a release request. */\nexport const borrowedRemote =\n (options: {\n readonly reference: SessionReference;\n readonly pendingWaitMillis?: number;\n readonly onCleanup?: (result: CleanupResult) => Effect.Effect<void>;\n }): RemoteSource<RemoteLease, SessionError> =>\n (local) =>\n Effect.gen(function* () {\n const client = yield* BrowserbaseClient;\n const sessions = yield* BrowserbaseSessions;\n const acquired = yield* attachRemote(options, local);\n\n return {\n ...withConnection(acquired),\n ...providerControls(client, sessions, acquired.reference),\n };\n });\n","import {\n Context,\n Crypto,\n Effect,\n Layer,\n type Option,\n type Redacted,\n Schema,\n type Scope,\n} from \"effect\";\nimport type { BrowserSession, OpenOptions } from \"effect-browser/browser\";\nimport type {\n ActionResult,\n AutomationOptions,\n BrowserPolicy,\n ClickRequest,\n Observation,\n} from \"effect-browser/browser-data\";\nimport * as BrowserRuntime from \"effect-browser/browser-runtime\";\nimport {\n BrowserError,\n Reasons,\n type BrowserOperation,\n type InitializationError,\n} from \"effect-browser/errors\";\n\nimport { BrowserbaseBrowserBinding } from \"./BrowserBinding.ts\";\nimport type { CleanupResult } from \"./Cleanup.ts\";\nimport { BrowserbaseClient } from \"./Client.ts\";\nimport type { AllocationError, ContextError, SessionError } from \"./Errors.ts\";\nimport type { LiveView } from \"./internal/browser/LiveView.ts\";\nimport { isList } from \"./internal/List.ts\";\nimport { borrowedRemote, ownedRemote, type RemoteLease } from \"./internal/session/Browser.ts\";\nimport type { ContextWriterPermit } from \"./internal/session/WriterFacts.ts\";\nimport { issuedUpload } from \"./internal/upload/Issued.ts\";\nimport type { LaunchRecipe } from \"./Launch.ts\";\nimport type { AllocationAttempt, SessionReference } from \"./References.ts\";\nimport { BrowserbaseSessions } from \"./Sessions.ts\";\nimport { DownloadObservation, type SelectFilesRequest } from \"./Transfers.ts\";\n\nexport type { LiveView } from \"./internal/browser/LiveView.ts\";\nexport type { FileSelection, SelectFilesRequest } from \"./Transfers.ts\";\n\n/** Host configuration. Credentials live in the Client; a model never selects these values. */\nexport interface BrowserOptions extends AutomationOptions {\n readonly launch: LaunchRecipe;\n /** Required whenever the launch recipe persists a context. */\n readonly contextWriter?: ContextWriterPermit;\n readonly onCleanup?: (result: CleanupResult) => Effect.Effect<void>;\n readonly onAllocationUncertain?: (attempt: AllocationAttempt) => Effect.Effect<void>;\n}\n\nexport interface Handoff {\n readonly token: Redacted.Redacted<string>;\n readonly view: LiveView;\n}\n\n/** Browserbase identity, remote artifacts and provider cleanup remain hosted capabilities. */\nexport interface BrowserbaseSession<E = never> extends BrowserSession<E> {\n readonly reference: SessionReference;\n readonly closeChecked: Effect.Effect<CleanupResult, BrowserError>;\n readonly clickForDownload: (\n request: ClickRequest,\n ) => Effect.Effect<DownloadObservation, BrowserError>;\n /** Attaches to an existing file input; an uploaded branch needs a receipt for this session. */\n readonly selectFiles: (request: SelectFilesRequest) => Effect.Effect<ActionResult, BrowserError>;\n /** Registers the chooser observation before the single click that opens it. */\n readonly clickForFileSelection: (\n request: SelectFilesRequest,\n ) => Effect.Effect<ActionResult, BrowserError>;\n readonly liveView: (expiresInSeconds?: number) => Effect.Effect<LiveView, BrowserError>;\n readonly beginHandoff: (expiresInSeconds?: number) => Effect.Effect<Handoff, BrowserError>;\n readonly resume: (\n token: Redacted.Redacted<string>,\n operatorReleasedControl: boolean,\n ) => Effect.Effect<Observation, BrowserError>;\n readonly detach: Effect.Effect<\n { readonly reference: SessionReference; readonly targetId: string },\n BrowserError\n >;\n readonly reconnect: (\n operatorReleasedControl: boolean,\n ) => Effect.Effect<Observation, BrowserError | InitializationError>;\n readonly close: Effect.Effect<CleanupResult>;\n readonly cleanupResult: Effect.Effect<Option.Option<CleanupResult>>;\n}\n\nexport interface AttachRequest<E = never, R = never> extends OpenOptions<E, R> {\n readonly policy: BrowserPolicy;\n /** The exact page to resume; without it the session must have exactly one page. */\n readonly target?: { readonly targetId: string };\n /** Bounded admission of a session the provider has not finished starting. */\n readonly pendingWaitMillis?: number;\n}\n\nexport interface BrowserAcquisition<E = never> {\n readonly reference: SessionReference;\n readonly attempt: AllocationAttempt;\n readonly failure: Effect.Effect<never, E | InitializationError>;\n readonly connect: Effect.Effect<BrowserbaseSession<E>, BrowserError | E | InitializationError>;\n readonly close: Effect.Effect<CleanupResult>;\n}\n\n/** Only receipts issued for this exact provider session may resolve to stored paths. */\nconst selection = (\n request: SelectFilesRequest,\n reference: SessionReference,\n operation: BrowserOperation,\n): Effect.Effect<BrowserRuntime.ResolvedFileSelection, BrowserError> =>\n Effect.suspend(() => {\n if (request.selection._tag === \"Inline\")\n return Effect.succeed<BrowserRuntime.ResolvedFileSelection>({\n _tag: \"Inline\",\n files: request.selection.files,\n });\n\n const uploads = request.selection.uploads;\n\n if (!isList(uploads) || uploads.length < 1 || uploads.length > 8)\n return Effect.fail(\n BrowserError.make({\n operation,\n reason: Reasons.Configuration.make({}),\n outcome: \"undispatched\",\n }),\n );\n const paths: string[] = [];\n\n for (const receipt of uploads) {\n const issued = issuedUpload(receipt);\n\n if (\n issued === undefined ||\n issued.reference.projectId !== reference.projectId ||\n issued.reference.sessionId !== reference.sessionId\n )\n return Effect.fail(\n BrowserError.make({\n operation,\n reason: Reasons.Authorization.make({}),\n outcome: \"undispatched\",\n }),\n );\n paths.push(issued.remotePath);\n }\n\n return Effect.succeed<BrowserRuntime.ResolvedFileSelection>({ _tag: \"Stored\", paths });\n });\n\nconst makeSession = <E>(\n connection: BrowserRuntime.Connection<SessionReference, E>,\n lifetime: RemoteLease,\n): BrowserbaseSession<E> => {\n const { session, operations } = connection;\n\n // Decorating the same object preserves its private capture and page-control associations.\n return Object.assign(session, {\n reference: lifetime.reference,\n closeChecked: session.closeChecked.pipe(Effect.andThen(lifetime.closeChecked)),\n clickForDownload: (request) =>\n operations.clickForDownload(request).pipe(\n Effect.flatMap((event) =>\n Schema.decodeEffect(DownloadObservation)({\n ...event,\n reference: lifetime.reference,\n }).pipe(\n Effect.mapError(() =>\n BrowserError.make({\n operation: \"download-action\",\n reason: Reasons.Malformed.make({}),\n outcome: \"unknown\",\n }),\n ),\n ),\n ),\n ),\n selectFiles: (request) =>\n selection(request, lifetime.reference, \"select-files\").pipe(\n Effect.flatMap((files) =>\n operations.selectFiles({ selector: request.selector, selection: files }),\n ),\n ),\n clickForFileSelection: (request) =>\n selection(request, lifetime.reference, \"file-chooser\").pipe(\n Effect.flatMap((files) =>\n operations.clickForFileSelection({ selector: request.selector, selection: files }),\n ),\n ),\n liveView: (ttl = 60) => operations.liveView(lifetime.liveView(ttl)),\n beginHandoff: (ttl = 60) => operations.beginHandoff(lifetime.liveView(ttl)),\n resume: operations.resume,\n detach: operations.detach,\n reconnect: operations.reconnect,\n close: lifetime.release,\n cleanupResult: lifetime.cleanupResult,\n } satisfies Omit<BrowserbaseSession<E>, Exclude<keyof BrowserSession<E>, \"closeChecked\">>);\n};\n\nexport class BrowserbaseBrowser extends Context.Service<\n BrowserbaseBrowser,\n {\n readonly acquire: <E = never, R = never>(\n policy: BrowserPolicy,\n request?: OpenOptions<E, R>,\n ) => Effect.Effect<\n BrowserAcquisition<E>,\n AllocationError | BrowserError | ContextError,\n Scope.Scope | Exclude<R, Scope.Scope>\n >;\n /** Borrowed control of a session this process did not allocate and will not release. */\n readonly attach: <E = never, R = never>(\n reference: SessionReference,\n request: AttachRequest<E, R>,\n ) => Effect.Effect<\n BrowserbaseSession<E>,\n BrowserError | SessionError | E | InitializationError,\n Scope.Scope | Exclude<R, Scope.Scope>\n >;\n readonly open: <E = never, R = never>(\n policy: BrowserPolicy,\n request?: OpenOptions<E, R>,\n ) => Effect.Effect<\n BrowserbaseSession<E>,\n AllocationError | BrowserError | ContextError | E | InitializationError,\n Scope.Scope | Exclude<R, Scope.Scope>\n >;\n }\n>()(\"effect-browserbase/Browser\") {\n /** Open through the configured account and browser service, in the caller's scope. */\n static open<E = never, R = never>(policy: BrowserPolicy, request?: OpenOptions<E, R>) {\n return Effect.flatMap(BrowserbaseBrowser, (browser) => browser.open(policy, request));\n }\n\n /** Allocate the provider lifetime before connecting, preserving its attempt and cleanup. */\n static acquire<E = never, R = never>(policy: BrowserPolicy, request?: OpenOptions<E, R>) {\n return Effect.flatMap(BrowserbaseBrowser, (browser) => browser.acquire(policy, request));\n }\n\n /** Borrow a provider session without acquiring release authority over it. */\n static attach<E = never, R = never>(reference: SessionReference, request: AttachRequest<E, R>) {\n return Effect.flatMap(BrowserbaseBrowser, (browser) => browser.attach(reference, request));\n }\n\n /** Allocation attempts, connection ids and handoff tokens come from the required `Crypto`. */\n static layer(\n options: BrowserOptions,\n ): Layer.Layer<\n BrowserbaseBrowser,\n BrowserError,\n BrowserbaseClient | BrowserbaseSessions | Crypto.Crypto\n > {\n return Layer.effect(\n BrowserbaseBrowser,\n Effect.gen(function* () {\n const client = yield* BrowserbaseClient;\n const sessions = yield* BrowserbaseSessions;\n const crypto = yield* Crypto.Crypto;\n const binding = yield* BrowserbaseBrowserBinding;\n\n if (options.launch.context?.persist === true && options.contextWriter === undefined)\n return yield* BrowserError.make({\n operation: \"configure\",\n reason: Reasons.ContextLease.make({}),\n outcome: \"undispatched\",\n });\n if (Object.prototype.hasOwnProperty.call(options, \"bootstrap\"))\n return yield* BrowserError.make({\n operation: \"configure\",\n reason: Reasons.Configuration.make({}),\n outcome: \"undispatched\",\n });\n\n const runtime = yield* BrowserRuntime.make({\n implementation: \"browserbase-playwright-cdp\",\n binding,\n automation: projected(options),\n viewport:\n options.launch.viewport._tag === \"Fixed\"\n ? { width: options.launch.viewport.width, height: options.launch.viewport.height }\n : { width: 1280, height: 720 },\n preserveViewport: options.launch.viewport._tag !== \"Fixed\",\n keepAlive: options.launch.keepAlive === true,\n });\n\n const source =\n <L extends BrowserRuntime.Lifetime, E>(\n remote: BrowserRuntime.Source<\n L,\n E,\n BrowserbaseClient | BrowserbaseSessions | Crypto.Crypto\n >,\n ): BrowserRuntime.Source<L, E> =>\n (cleanup, deadline) =>\n remote(cleanup, deadline).pipe(\n Effect.provideService(BrowserbaseClient, client),\n Effect.provideService(BrowserbaseSessions, sessions),\n Effect.provideService(Crypto.Crypto, crypto),\n );\n\n const acquire = Effect.fnUntraced(function* <E = never, R = never>(\n policy: BrowserPolicy,\n request: OpenOptions<E, R> = {},\n ) {\n const acquired = yield* runtime.acquire(\n policy,\n source(\n ownedRemote({\n launch: options.launch,\n ...(options.contextWriter === undefined\n ? {}\n : { contextWriter: options.contextWriter }),\n ...(options.onCleanup === undefined ? {} : { onCleanup: options.onCleanup }),\n ...(options.onAllocationUncertain === undefined\n ? {}\n : { onAllocationUncertain: options.onAllocationUncertain }),\n }),\n ),\n request,\n );\n\n const connected = yield* Effect.cached(\n acquired.connect.pipe(\n Effect.map((connection) => makeSession(connection, acquired.lifetime)),\n ),\n );\n\n return {\n reference: acquired.reference,\n attempt: acquired.lifetime.attempt,\n failure: acquired.failure,\n close: acquired.close,\n connect: acquired.connect.pipe(Effect.andThen(connected)),\n } satisfies BrowserAcquisition<E>;\n });\n\n const attach = Effect.fnUntraced(function* <E = never, R = never>(\n reference: SessionReference,\n request: AttachRequest<E, R>,\n ) {\n const acquired = yield* runtime.acquire(\n request.policy,\n source(\n borrowedRemote({\n reference,\n ...(request.pendingWaitMillis === undefined\n ? {}\n : { pendingWaitMillis: request.pendingWaitMillis }),\n ...(options.onCleanup === undefined ? {} : { onCleanup: options.onCleanup }),\n }),\n ),\n {\n ...(request.bootstrap === undefined ? {} : { bootstrap: request.bootstrap }),\n existingTarget: request.target ?? {},\n },\n );\n\n return yield* acquired.connect.pipe(\n Effect.map((connection) => makeSession(connection, acquired.lifetime)),\n );\n });\n\n return BrowserbaseBrowser.of({\n acquire,\n attach,\n open: (policy, request) =>\n acquire(policy, request).pipe(Effect.flatMap((acquired) => acquired.connect)),\n });\n }),\n );\n }\n}\n\n/** Only the automation fields cross the schema boundary; launch and callbacks are separate. */\nconst projected = (options: BrowserOptions) => ({\n ...(options.maxHostReads === undefined ? {} : { maxHostReads: options.maxHostReads }),\n ...(options.actionTimeoutMillis === undefined\n ? {}\n : { actionTimeoutMillis: options.actionTimeoutMillis }),\n ...(options.maxPages === undefined ? {} : { maxPages: options.maxPages }),\n ...(options.initialPage === undefined ? {} : { initialPage: options.initialPage }),\n ...(options.popupPolicy === undefined ? {} : { popupPolicy: options.popupPolicy }),\n ...(options.dialogPolicy === undefined ? {} : { dialogPolicy: options.dialogPolicy }),\n ...(options.pageControl === undefined ? {} : { pageControl: options.pageControl }),\n});\n"],"mappings":"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"}
package/dist/Browser.mjs CHANGED
@@ -1,3 +1,3 @@
1
1
  import "./BrowserBinding.mjs";
2
- import { t as BrowserbaseBrowser } from "./Browser-Dw0JFTaD.mjs";
2
+ import { t as BrowserbaseBrowser } from "./Browser-BPcF550A.mjs";
3
3
  export { BrowserbaseBrowser };
@@ -1,14 +1,28 @@
1
1
  import { n as ContextReference } from "./References-DOH3Wu44.mjs";
2
- import { ContextError } from "./Errors.mjs";
2
+ import { ContextError, SessionError } from "./Errors.mjs";
3
+ import { t as BrowserbaseSessions } from "./Sessions-oJEUmZth.mjs";
3
4
  import { a as WriterLease, i as WriterAttemptFacts, n as ContextWriterPermit, o as WriterOptions, r as PersistenceEvidence, s as WriterSettlementFacts, t as ContextWriterBackend } from "./WriterFacts-BBJRDZYY.mjs";
4
5
  import { Effect, Scope } from "effect";
5
6
  //#region src/ContextCoordination.d.ts
6
7
  /**
7
8
  * Owns the backend lease, child browser scopes, and exact attempt evidence. The backend must
8
9
  * handle uncertain distributed lease acquisition itself. It must persist quarantine facts;
9
- * a local Scope closing is never permission to admit another remote writer.
10
+ * a local Scope closing is never permission to admit another remote writer. A writer that
11
+ * settles as anything but a release leaves its Context refused in this process until
12
+ * `reconcile` succeeds.
10
13
  */
11
14
  export declare const withWriter: <A, E, R, LeaseE, LeaseR, VerifyE = never, VerifyR = never>(backend: ContextWriterBackend<LeaseE, LeaseR>, reference: ContextReference, use: (permit: ContextWriterPermit) => Effect.Effect<A, E, R>, options?: WriterOptions<A, VerifyE, VerifyR>) => Effect.Effect<A, E | LeaseE | VerifyE | ContextError, Exclude<R | LeaseR | VerifyR, Scope.Scope>>;
15
+ /**
16
+ * Lifts this process's quarantine on a Context once no writer it admitted can still write:
17
+ * the provider reports every session the quarantined writer recorded as terminal, and then
18
+ * the consumer's readback of the Context passes. The Context stays held throughout, so no
19
+ * writer is admitted against evidence still being gathered; a live writer is refused rather
20
+ * than waited for. An allocation whose outcome stayed unknown names no session to check, so
21
+ * its Context stays refused. Ending a session is the caller's explicit request; this only
22
+ * reads status. With no quarantine held here, only the readback runs. The backend keeps its
23
+ * own quarantine until the consumer reports this reconciliation to it.
24
+ */
25
+ export declare const reconcile: <E, R>(reference: ContextReference, readback: Effect.Effect<void, E, R>) => Effect.Effect<void, E | ContextError | SessionError, BrowserbaseSessions | Exclude<R, Scope.Scope>>;
12
26
  //#endregion
13
27
  export { type ContextWriterBackend, type ContextWriterPermit, PersistenceEvidence, WriterAttemptFacts, type WriterLease, type WriterOptions, WriterSettlementFacts };
14
28
  export {};
@@ -1,19 +1,24 @@
1
1
  import { ContextReference } from "./References.mjs";
2
2
  import { ContextError } from "./Errors.mjs";
3
- import { a as PersistenceEvidence, n as isContextWriterBusy, o as WriterAttemptFacts, r as makeContextWriterPermit, s as WriterSettlementFacts, t as closeContextWriterPermit } from "./ContextWriter-oKWFLHuP.mjs";
3
+ import { isTerminalSessionStatus } from "./SessionData.mjs";
4
+ import { c as WriterSettlementFacts, i as makeContextWriterPermit, n as closeContextWriterPermit, o as PersistenceEvidence, r as isContextWriterBusy, s as WriterAttemptFacts, t as claimReconciliation } from "./ContextWriter-CiEma24z.mjs";
5
+ import { t as BrowserbaseSessions } from "./Sessions-BUoyPcPJ.mjs";
4
6
  import { Clock, Effect, Exit, Schema } from "effect";
5
7
  //#region src/ContextCoordination.ts
8
+ const decodeReference = (reference, operation) => Schema.decodeEffect(ContextReference)(reference, { onExcessProperty: "error" }).pipe(Effect.mapError(() => ContextError.make({
9
+ operation,
10
+ reason: "configuration",
11
+ outcome: "undispatched"
12
+ })));
6
13
  /**
7
14
  * Owns the backend lease, child browser scopes, and exact attempt evidence. The backend must
8
15
  * handle uncertain distributed lease acquisition itself. It must persist quarantine facts;
9
- * a local Scope closing is never permission to admit another remote writer.
16
+ * a local Scope closing is never permission to admit another remote writer. A writer that
17
+ * settles as anything but a release leaves its Context refused in this process until
18
+ * `reconcile` succeeds.
10
19
  */
11
20
  const withWriter = (backend, reference, use, options = {}) => Effect.scoped(Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
12
- const ref = yield* Schema.decodeEffect(ContextReference)(reference, { onExcessProperty: "error" }).pipe(Effect.mapError(() => ContextError.make({
13
- operation: "writer",
14
- reason: "configuration",
15
- outcome: "undispatched"
16
- })));
21
+ const ref = yield* decodeReference(reference, "writer");
17
22
  const timeout = options.settlementTimeoutMillis ?? 5e3;
18
23
  if (!Number.isSafeInteger(timeout) || timeout < 1 || timeout > 6e4 || isContextWriterBusy(ref)) return yield* ContextError.make({
19
24
  operation: "writer",
@@ -23,7 +28,7 @@ const withWriter = (backend, reference, use, options = {}) => Effect.scoped(Effe
23
28
  const permit = yield* makeContextWriterPermit(ref);
24
29
  const acquired = yield* restore(backend.acquire(ref)).pipe(Effect.exit);
25
30
  if (Exit.isFailure(acquired)) {
26
- closeContextWriterPermit(permit, false);
31
+ closeContextWriterPermit(permit, true);
27
32
  return yield* Effect.failCause(acquired.cause);
28
33
  }
29
34
  const lease = acquired.value;
@@ -54,7 +59,35 @@ const withWriter = (backend, reference, use, options = {}) => Effect.scoped(Effe
54
59
  if (Exit.isFailure(settlement)) return yield* Effect.failCause(settlement.cause);
55
60
  return body.value;
56
61
  })));
62
+ /**
63
+ * Lifts this process's quarantine on a Context once no writer it admitted can still write:
64
+ * the provider reports every session the quarantined writer recorded as terminal, and then
65
+ * the consumer's readback of the Context passes. The Context stays held throughout, so no
66
+ * writer is admitted against evidence still being gathered; a live writer is refused rather
67
+ * than waited for. An allocation whose outcome stayed unknown names no session to check, so
68
+ * its Context stays refused. Ending a session is the caller's explicit request; this only
69
+ * reads status. With no quarantine held here, only the readback runs. The backend keeps its
70
+ * own quarantine until the consumer reports this reconciliation to it.
71
+ */
72
+ const reconcile = (reference, readback) => Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
73
+ const ref = yield* decodeReference(reference, "writer-reconcile");
74
+ const sessions = yield* BrowserbaseSessions;
75
+ const claim = yield* claimReconciliation(ref);
76
+ const checked = yield* restore(Effect.gen(function* () {
77
+ for (const entry of yield* claim.attempts) {
78
+ if (entry.state === "rejected") continue;
79
+ if (!(entry.session !== void 0 && isTerminalSessionStatus((yield* sessions.retrieve(entry.session)).status))) return yield* ContextError.make({
80
+ operation: "writer-reconcile",
81
+ reason: "active",
82
+ outcome: "undispatched"
83
+ });
84
+ }
85
+ yield* Effect.scoped(readback);
86
+ })).pipe(Effect.exit);
87
+ claim.finish(Exit.isSuccess(checked));
88
+ return yield* checked;
89
+ }));
57
90
  //#endregion
58
- export { PersistenceEvidence, WriterAttemptFacts, WriterSettlementFacts, withWriter };
91
+ export { PersistenceEvidence, WriterAttemptFacts, WriterSettlementFacts, reconcile, withWriter };
59
92
 
60
93
  //# sourceMappingURL=ContextCoordination.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ContextCoordination.mjs","names":[],"sources":["../src/ContextCoordination.ts"],"sourcesContent":["import { Clock, Effect, Exit, Schema, type Scope } from \"effect\";\n\nimport { ContextError } from \"./Errors.ts\";\nimport {\n makeContextWriterPermit,\n closeContextWriterPermit,\n isContextWriterBusy,\n} from \"./internal/session/ContextWriter.ts\";\nimport type {\n ContextWriterBackend,\n ContextWriterPermit,\n WriterOptions,\n} from \"./internal/session/WriterFacts.ts\";\nimport { ContextReference } from \"./References.ts\";\n\nexport {\n PersistenceEvidence,\n WriterAttemptFacts,\n WriterSettlementFacts,\n type ContextWriterBackend,\n type ContextWriterPermit,\n type WriterLease,\n type WriterOptions,\n} from \"./internal/session/WriterFacts.ts\";\n\n/**\n * Owns the backend lease, child browser scopes, and exact attempt evidence. The backend must\n * handle uncertain distributed lease acquisition itself. It must persist quarantine facts;\n * a local Scope closing is never permission to admit another remote writer.\n */\nexport const withWriter = <A, E, R, LeaseE, LeaseR, VerifyE = never, VerifyR = never>(\n backend: ContextWriterBackend<LeaseE, LeaseR>,\n reference: ContextReference,\n use: (permit: ContextWriterPermit) => Effect.Effect<A, E, R>,\n options: WriterOptions<A, VerifyE, VerifyR> = {},\n): Effect.Effect<\n A,\n E | LeaseE | VerifyE | ContextError,\n Exclude<R | LeaseR | VerifyR, Scope.Scope>\n> =>\n Effect.scoped(\n Effect.uninterruptibleMask((restore) =>\n Effect.gen(function* () {\n const ref = yield* Schema.decodeEffect(ContextReference)(reference, {\n onExcessProperty: \"error\",\n }).pipe(\n Effect.mapError(() =>\n ContextError.make({\n operation: \"writer\",\n reason: \"configuration\",\n outcome: \"undispatched\",\n }),\n ),\n );\n\n const timeout = options.settlementTimeoutMillis ?? 5000;\n\n if (\n !Number.isSafeInteger(timeout) ||\n timeout < 1 ||\n timeout > 60000 ||\n isContextWriterBusy(ref)\n ) {\n return yield* ContextError.make({\n operation: \"writer\",\n reason: isContextWriterBusy(ref) ? \"active\" : \"configuration\",\n outcome: \"undispatched\",\n });\n }\n const permit = yield* makeContextWriterPermit(ref);\n const acquired = yield* restore(backend.acquire(ref)).pipe(Effect.exit);\n\n if (Exit.isFailure(acquired)) {\n closeContextWriterPermit(permit, false);\n\n return yield* Effect.failCause(acquired.cause);\n }\n const lease = acquired.value;\n\n const body = yield* restore(Effect.scoped(Effect.suspend(() => use(permit)))).pipe(\n Effect.exit,\n );\n\n // Every remote-resource finalizer in use() has run before any settlement/readback below.\n if (Exit.isFailure(body)) yield* permit.quarantine;\n let verification: Exit.Exit<void, VerifyE | ContextError> = Exit.void;\n\n if (Exit.isSuccess(body) && options.verify !== undefined) {\n verification = yield* restore(Effect.scoped(options.verify(body.value))).pipe(\n Effect.exit,\n );\n if (Exit.isSuccess(verification)) {\n verification = yield* permit\n .confirmReadback(yield* Clock.currentTimeMillis)\n .pipe(Effect.exit);\n } else yield* permit.quarantine;\n }\n const facts = yield* permit.snapshot;\n\n const settlement = yield* restore(lease.settle(facts)).pipe(\n Effect.timeoutOrElse({\n duration: timeout,\n orElse: () =>\n Effect.fail(\n ContextError.make({\n operation: \"writer-settle\",\n reason: \"timeout\",\n outcome: \"unknown\",\n }),\n ),\n }),\n Effect.exit,\n );\n\n if (Exit.isFailure(settlement)) yield* permit.quarantine;\n closeContextWriterPermit(\n permit,\n Exit.isSuccess(settlement) && facts.disposition === \"release\",\n );\n // Preserve the primary cause; secondary failure is visible in the retained quarantine and\n // a content-free diagnostic. Never serialize arbitrary consumer/database error values.\n if (Exit.isFailure(body)) {\n if (Exit.isFailure(settlement))\n yield* Effect.logError(\"Browserbase writer settlement remained unconfirmed\");\n\n return yield* Effect.failCause(body.cause);\n }\n if (Exit.isFailure(verification)) return yield* Effect.failCause(verification.cause);\n if (Exit.isFailure(settlement)) return yield* Effect.failCause(settlement.cause);\n\n return body.value;\n }),\n ),\n );\n"],"mappings":";;;;;;;;;;AA8BA,MAAa,cACX,SACA,WACA,KACA,UAA8C,CAAC,MAM/C,OAAO,OACL,OAAO,qBAAqB,YAC1B,OAAO,IAAI,aAAa;CACtB,MAAM,MAAM,OAAO,OAAO,aAAa,gBAAgB,CAAC,CAAC,WAAW,EAClE,kBAAkB,QACpB,CAAC,CAAC,CAAC,KACD,OAAO,eACL,aAAa,KAAK;EAChB,WAAW;EACX,QAAQ;EACR,SAAS;CACX,CAAC,CACH,CACF;CAEA,MAAM,UAAU,QAAQ,2BAA2B;CAEnD,IACE,CAAC,OAAO,cAAc,OAAO,KAC7B,UAAU,KACV,UAAU,OACV,oBAAoB,GAAG,GAEvB,OAAO,OAAO,aAAa,KAAK;EAC9B,WAAW;EACX,QAAQ,oBAAoB,GAAG,IAAI,WAAW;EAC9C,SAAS;CACX,CAAC;CAEH,MAAM,SAAS,OAAO,wBAAwB,GAAG;CACjD,MAAM,WAAW,OAAO,QAAQ,QAAQ,QAAQ,GAAG,CAAC,CAAC,CAAC,KAAK,OAAO,IAAI;CAEtE,IAAI,KAAK,UAAU,QAAQ,GAAG;EAC5B,yBAAyB,QAAQ,KAAK;EAEtC,OAAO,OAAO,OAAO,UAAU,SAAS,KAAK;CAC/C;CACA,MAAM,QAAQ,SAAS;CAEvB,MAAM,OAAO,OAAO,QAAQ,OAAO,OAAO,OAAO,cAAc,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAC5E,OAAO,IACT;CAGA,IAAI,KAAK,UAAU,IAAI,GAAG,OAAO,OAAO;CACxC,IAAI,eAAwD,KAAK;CAEjE,IAAI,KAAK,UAAU,IAAI,KAAK,QAAQ,WAAW,KAAA,GAAW;EACxD,eAAe,OAAO,QAAQ,OAAO,OAAO,QAAQ,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,KACvE,OAAO,IACT;EACA,IAAI,KAAK,UAAU,YAAY,GAC7B,eAAe,OAAO,OACnB,gBAAgB,OAAO,MAAM,iBAAiB,CAAC,CAC/C,KAAK,OAAO,IAAI;OACd,OAAO,OAAO;CACvB;CACA,MAAM,QAAQ,OAAO,OAAO;CAE5B,MAAM,aAAa,OAAO,QAAQ,MAAM,OAAO,KAAK,CAAC,CAAC,CAAC,KACrD,OAAO,cAAc;EACnB,UAAU;EACV,cACE,OAAO,KACL,aAAa,KAAK;GAChB,WAAW;GACX,QAAQ;GACR,SAAS;EACX,CAAC,CACH;CACJ,CAAC,GACD,OAAO,IACT;CAEA,IAAI,KAAK,UAAU,UAAU,GAAG,OAAO,OAAO;CAC9C,yBACE,QACA,KAAK,UAAU,UAAU,KAAK,MAAM,gBAAgB,SACtD;CAGA,IAAI,KAAK,UAAU,IAAI,GAAG;EACxB,IAAI,KAAK,UAAU,UAAU,GAC3B,OAAO,OAAO,SAAS,oDAAoD;EAE7E,OAAO,OAAO,OAAO,UAAU,KAAK,KAAK;CAC3C;CACA,IAAI,KAAK,UAAU,YAAY,GAAG,OAAO,OAAO,OAAO,UAAU,aAAa,KAAK;CACnF,IAAI,KAAK,UAAU,UAAU,GAAG,OAAO,OAAO,OAAO,UAAU,WAAW,KAAK;CAE/E,OAAO,KAAK;AACd,CAAC,CACH,CACF"}
1
+ {"version":3,"file":"ContextCoordination.mjs","names":[],"sources":["../src/ContextCoordination.ts"],"sourcesContent":["import { Clock, Effect, Exit, Schema, type Scope } from \"effect\";\n\nimport { ContextError, type SessionError } from \"./Errors.ts\";\nimport {\n claimReconciliation,\n makeContextWriterPermit,\n closeContextWriterPermit,\n isContextWriterBusy,\n} from \"./internal/session/ContextWriter.ts\";\nimport type {\n ContextWriterBackend,\n ContextWriterPermit,\n WriterOptions,\n} from \"./internal/session/WriterFacts.ts\";\nimport { ContextReference } from \"./References.ts\";\nimport { isTerminalSessionStatus } from \"./SessionData.ts\";\nimport { BrowserbaseSessions } from \"./Sessions.ts\";\n\nexport {\n PersistenceEvidence,\n WriterAttemptFacts,\n WriterSettlementFacts,\n type ContextWriterBackend,\n type ContextWriterPermit,\n type WriterLease,\n type WriterOptions,\n} from \"./internal/session/WriterFacts.ts\";\n\nconst decodeReference = (reference: ContextReference, operation: \"writer\" | \"writer-reconcile\") =>\n Schema.decodeEffect(ContextReference)(reference, { onExcessProperty: \"error\" }).pipe(\n Effect.mapError(() =>\n ContextError.make({ operation, reason: \"configuration\", outcome: \"undispatched\" }),\n ),\n );\n\n/**\n * Owns the backend lease, child browser scopes, and exact attempt evidence. The backend must\n * handle uncertain distributed lease acquisition itself. It must persist quarantine facts;\n * a local Scope closing is never permission to admit another remote writer. A writer that\n * settles as anything but a release leaves its Context refused in this process until\n * `reconcile` succeeds.\n */\nexport const withWriter = <A, E, R, LeaseE, LeaseR, VerifyE = never, VerifyR = never>(\n backend: ContextWriterBackend<LeaseE, LeaseR>,\n reference: ContextReference,\n use: (permit: ContextWriterPermit) => Effect.Effect<A, E, R>,\n options: WriterOptions<A, VerifyE, VerifyR> = {},\n): Effect.Effect<\n A,\n E | LeaseE | VerifyE | ContextError,\n Exclude<R | LeaseR | VerifyR, Scope.Scope>\n> =>\n Effect.scoped(\n Effect.uninterruptibleMask((restore) =>\n Effect.gen(function* () {\n const ref = yield* decodeReference(reference, \"writer\");\n\n const timeout = options.settlementTimeoutMillis ?? 5000;\n\n if (\n !Number.isSafeInteger(timeout) ||\n timeout < 1 ||\n timeout > 60000 ||\n isContextWriterBusy(ref)\n ) {\n return yield* ContextError.make({\n operation: \"writer\",\n reason: isContextWriterBusy(ref) ? \"active\" : \"configuration\",\n outcome: \"undispatched\",\n });\n }\n const permit = yield* makeContextWriterPermit(ref);\n const acquired = yield* restore(backend.acquire(ref)).pipe(Effect.exit);\n\n if (Exit.isFailure(acquired)) {\n // `use` never received the permit, so no allocation was attempted under it and this\n // process admitted no remote writer. What the failed acquisition left uncertain\n // remotely is the backend's to resolve.\n closeContextWriterPermit(permit, true);\n\n return yield* Effect.failCause(acquired.cause);\n }\n const lease = acquired.value;\n\n const body = yield* restore(Effect.scoped(Effect.suspend(() => use(permit)))).pipe(\n Effect.exit,\n );\n\n // Every remote-resource finalizer in use() has run before any settlement/readback below.\n if (Exit.isFailure(body)) yield* permit.quarantine;\n let verification: Exit.Exit<void, VerifyE | ContextError> = Exit.void;\n\n if (Exit.isSuccess(body) && options.verify !== undefined) {\n verification = yield* restore(Effect.scoped(options.verify(body.value))).pipe(\n Effect.exit,\n );\n if (Exit.isSuccess(verification)) {\n verification = yield* permit\n .confirmReadback(yield* Clock.currentTimeMillis)\n .pipe(Effect.exit);\n } else yield* permit.quarantine;\n }\n const facts = yield* permit.snapshot;\n\n const settlement = yield* restore(lease.settle(facts)).pipe(\n Effect.timeoutOrElse({\n duration: timeout,\n orElse: () =>\n Effect.fail(\n ContextError.make({\n operation: \"writer-settle\",\n reason: \"timeout\",\n outcome: \"unknown\",\n }),\n ),\n }),\n Effect.exit,\n );\n\n if (Exit.isFailure(settlement)) yield* permit.quarantine;\n closeContextWriterPermit(\n permit,\n Exit.isSuccess(settlement) && facts.disposition === \"release\",\n );\n // Preserve the primary cause; secondary failure is visible in the retained quarantine and\n // a content-free diagnostic. Never serialize arbitrary consumer/database error values.\n if (Exit.isFailure(body)) {\n if (Exit.isFailure(settlement))\n yield* Effect.logError(\"Browserbase writer settlement remained unconfirmed\");\n\n return yield* Effect.failCause(body.cause);\n }\n if (Exit.isFailure(verification)) return yield* Effect.failCause(verification.cause);\n if (Exit.isFailure(settlement)) return yield* Effect.failCause(settlement.cause);\n\n return body.value;\n }),\n ),\n );\n\n/**\n * Lifts this process's quarantine on a Context once no writer it admitted can still write:\n * the provider reports every session the quarantined writer recorded as terminal, and then\n * the consumer's readback of the Context passes. The Context stays held throughout, so no\n * writer is admitted against evidence still being gathered; a live writer is refused rather\n * than waited for. An allocation whose outcome stayed unknown names no session to check, so\n * its Context stays refused. Ending a session is the caller's explicit request; this only\n * reads status. With no quarantine held here, only the readback runs. The backend keeps its\n * own quarantine until the consumer reports this reconciliation to it.\n */\nexport const reconcile = <E, R>(\n reference: ContextReference,\n readback: Effect.Effect<void, E, R>,\n): Effect.Effect<\n void,\n E | ContextError | SessionError,\n BrowserbaseSessions | Exclude<R, Scope.Scope>\n> =>\n Effect.uninterruptibleMask((restore) =>\n Effect.gen(function* () {\n const ref = yield* decodeReference(reference, \"writer-reconcile\");\n const sessions = yield* BrowserbaseSessions;\n const claim = yield* claimReconciliation(ref);\n\n const checked = yield* restore(\n Effect.gen(function* () {\n for (const entry of yield* claim.attempts) {\n // A rejected creation made no session. Any other attempt must name a session the\n // provider has ended, and the readback must come after every one of them.\n if (entry.state === \"rejected\") continue;\n\n const ended =\n entry.session !== undefined &&\n isTerminalSessionStatus((yield* sessions.retrieve(entry.session)).status);\n\n if (!ended) {\n return yield* ContextError.make({\n operation: \"writer-reconcile\",\n reason: \"active\",\n outcome: \"undispatched\",\n });\n }\n }\n yield* Effect.scoped(readback);\n }),\n ).pipe(Effect.exit);\n\n claim.finish(Exit.isSuccess(checked));\n\n return yield* checked;\n }),\n );\n"],"mappings":"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"}
@@ -163,12 +163,33 @@ const makeContextWriterPermit = (reference) => Effect.suspend(() => {
163
163
  closed = true;
164
164
  if (active.get(key(owned)) !== permit) return;
165
165
  if (released) active.delete(key(owned));
166
- else active.set(key(owned), "quarantined");
166
+ else active.set(key(owned), {
167
+ _tag: "Quarantined",
168
+ permit
169
+ });
167
170
  });
168
171
  return Effect.succeed(permit);
169
172
  });
170
173
  const retirement = /* @__PURE__ */ new WeakMap();
171
174
  const closeContextWriterPermit = (permit, released) => retirement.get(permit)?.(released);
175
+ const claimReconciliation = (reference) => Effect.suspend(() => {
176
+ const held = active.get(key(reference));
177
+ if (held?._tag === "ContextWriterPermit" || held?._tag === "Reconciling" || held === void 0 && active.size >= 2048) return Effect.fail(ContextError.make({
178
+ operation: "writer-reconcile",
179
+ reason: "active",
180
+ outcome: "undispatched"
181
+ }));
182
+ const claim = { _tag: "Reconciling" };
183
+ active.set(key(reference), claim);
184
+ return Effect.succeed({
185
+ attempts: held === void 0 ? Effect.succeed([]) : held.permit.snapshot.pipe(Effect.map((facts) => facts.attempts)),
186
+ finish: (reconciled) => {
187
+ if (active.get(key(reference)) !== claim) return;
188
+ if (reconciled || held === void 0) active.delete(key(reference));
189
+ else active.set(key(reference), held);
190
+ }
191
+ });
192
+ });
172
193
  const requireContextWriterPermit = (permit, reference) => Effect.suspend(() => {
173
194
  const actual = authentic.get(permit);
174
195
  return actual !== void 0 && active.get(key(reference)) === actual && actual.reference.contextId === reference.contextId && actual.reference.projectId === reference.projectId ? Effect.succeed(actual) : Effect.fail(ContextError.make({
@@ -178,6 +199,6 @@ const requireContextWriterPermit = (permit, reference) => Effect.suspend(() => {
178
199
  }));
179
200
  });
180
201
  //#endregion
181
- export { PersistenceEvidence as a, requireContextWriterPermit as i, isContextWriterBusy as n, WriterAttemptFacts as o, makeContextWriterPermit as r, WriterSettlementFacts as s, closeContextWriterPermit as t };
202
+ export { requireContextWriterPermit as a, WriterSettlementFacts as c, makeContextWriterPermit as i, closeContextWriterPermit as n, PersistenceEvidence as o, isContextWriterBusy as r, WriterAttemptFacts as s, claimReconciliation as t };
182
203
 
183
- //# sourceMappingURL=ContextWriter-oKWFLHuP.mjs.map
204
+ //# sourceMappingURL=ContextWriter-CiEma24z.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ContextWriter-CiEma24z.mjs","names":[],"sources":["../src/internal/session/WriterFacts.ts","../src/internal/session/ContextWriter.ts"],"sourcesContent":["import { type Effect, Schema } from \"effect\";\n\nimport { CleanupResult } from \"../../Cleanup.ts\";\nimport { AllocationAttempt, ContextReference, SessionReference } from \"../../References.ts\";\n\n/**\n * The writer vocabulary both the public coordination entry point and the permit\n * implementation need. Keeping it here leaves one direction of dependency:\n * `ContextCoordination` and `ContextWriter` both read this module, never each other.\n */\nexport const PersistenceEvidence = Schema.Union([\n Schema.TaggedStruct(\"NotRequested\", {}),\n Schema.TaggedStruct(\"Unconfirmed\", {\n reason: Schema.Literals([\"writer-active\", \"writer-unknown\", \"flush-unacknowledged\"]),\n }),\n Schema.TaggedStruct(\"Observed\", {\n method: Schema.Literal(\"consumer-readback\"),\n observedAtMillis: Schema.Finite,\n }),\n]);\n\nexport type PersistenceEvidence = typeof PersistenceEvidence.Type;\n\nexport class WriterAttemptFacts extends Schema.Class<WriterAttemptFacts>(\n \"BrowserbaseWriterAttemptFacts\",\n)({\n attempt: AllocationAttempt,\n session: Schema.optionalKey(SessionReference),\n state: Schema.Literals([\"admitted\", \"rejected\", \"unknown\", \"terminal\"]),\n cleanup: Schema.optionalKey(CleanupResult),\n}) {}\n\nexport class WriterSettlementFacts extends Schema.Class<WriterSettlementFacts>(\n \"BrowserbaseWriterSettlementFacts\",\n)({\n reference: ContextReference,\n attempts: Schema.Array(WriterAttemptFacts).check(Schema.isMaxLength(64)),\n persistence: PersistenceEvidence,\n disposition: Schema.Literals([\"release\", \"quarantine\"]),\n}) {}\n\nexport interface WriterLease<E, R> {\n readonly settle: (facts: WriterSettlementFacts) => Effect.Effect<void, E, R>;\n}\n\nexport interface ContextWriterBackend<E, R> {\n readonly acquire: (reference: ContextReference) => Effect.Effect<WriterLease<E, R>, E, R>;\n}\n\nexport interface ContextWriterPermit {\n readonly _tag: \"ContextWriterPermit\";\n readonly reference: ContextReference;\n}\n\nexport interface WriterOptions<A, VerifyE, VerifyR> {\n /** Bounded consumer-controlled readback, not a provider-wide flush acknowledgement. */\n readonly verify?: (value: A) => Effect.Effect<void, VerifyE, VerifyR>;\n readonly settlementTimeoutMillis?: number;\n}\n","import { Effect } from \"effect\";\n\nimport type { CleanupResult } from \"../../Cleanup.ts\";\nimport { ContextError } from \"../../Errors.ts\";\nimport type { AllocationAttempt, ContextReference, SessionReference } from \"../../References.ts\";\nimport {\n type ContextWriterPermit,\n type PersistenceEvidence,\n WriterAttemptFacts,\n WriterSettlementFacts,\n} from \"./WriterFacts.ts\";\n\n/** There is one record per exact allocation attempt, not parallel uncorrelated arrays. */\ninterface AttemptRecord {\n readonly attempt: AllocationAttempt;\n session?: SessionReference;\n state: \"admitted\" | \"rejected\" | \"unknown\" | \"terminal\";\n cleanup?: CleanupResult;\n}\n\nexport interface ContextWriterPermitInternal extends ContextWriterPermit {\n readonly recordAttempt: (attempt: AllocationAttempt) => Effect.Effect<void, ContextError>;\n readonly recordSession: (attempt: AllocationAttempt, reference: SessionReference) => void;\n readonly rejected: (attempt: AllocationAttempt) => void;\n readonly uncertain: (attempt: AllocationAttempt) => void;\n readonly completed: (attempt: AllocationAttempt, cleanup: CleanupResult) => void;\n readonly confirmReadback: (atMillis: number) => Effect.Effect<void, ContextError>;\n readonly quarantine: Effect.Effect<void>;\n readonly snapshot: Effect.Effect<WriterSettlementFacts>;\n}\n\n/** A writer retired without release. Its permit keeps collecting late evidence for reconciliation. */\ninterface Quarantine {\n readonly _tag: \"Quarantined\";\n readonly permit: ContextWriterPermitInternal;\n}\n\n/** Holds a Context while reconciliation checks it, so no writer is admitted against that evidence. */\ninterface Reconciliation {\n readonly _tag: \"Reconciling\";\n}\n\nconst authentic = new WeakMap<ContextWriterPermit, ContextWriterPermitInternal>();\nconst active = new Map<string, ContextWriterPermitInternal | Quarantine | Reconciliation>();\nconst key = (ref: ContextReference) => `${ref.projectId}/${ref.contextId}`;\n\nexport const isContextWriterBusy = (ref: ContextReference): boolean => active.has(key(ref));\n\nexport const makeContextWriterPermit = (\n reference: ContextReference,\n): Effect.Effect<ContextWriterPermitInternal, ContextError> =>\n Effect.suspend(() => {\n if (active.has(key(reference)) || active.size >= 2048)\n return Effect.fail(\n ContextError.make({ operation: \"writer\", reason: \"active\", outcome: \"undispatched\" }),\n );\n const owned = Object.freeze(reference);\n const attempts = new Map<string, AttemptRecord>();\n\n let closed = false,\n quarantined = false;\n\n let persistence: PersistenceEvidence = { _tag: \"NotRequested\" };\n\n const unknown = () => {\n quarantined = true;\n persistence = { _tag: \"Unconfirmed\", reason: \"writer-unknown\" };\n };\n\n const noActive = () =>\n [...attempts.values()].every(\n (entry) => entry.state === \"rejected\" || entry.state === \"terminal\",\n );\n\n const permit: ContextWriterPermitInternal = {\n _tag: \"ContextWriterPermit\",\n reference: owned,\n recordAttempt: (attempt) =>\n Effect.suspend(() => {\n if (\n closed ||\n quarantined ||\n !noActive() ||\n attempt.projectId !== owned.projectId ||\n (attempts.size > 0 && persistence._tag === \"Unconfirmed\")\n ) {\n return Effect.fail(\n ContextError.make({\n operation: \"writer-admit\",\n reason: \"active\",\n outcome: \"undispatched\",\n }),\n );\n }\n if (attempts.has(attempt.attemptId) || attempts.size >= 64)\n return Effect.fail(\n ContextError.make({\n operation: \"writer-admit\",\n reason: \"limit\",\n outcome: \"undispatched\",\n }),\n );\n const copy = Object.freeze(attempt);\n\n attempts.set(copy.attemptId, { attempt: copy, state: \"admitted\" });\n persistence = { _tag: \"Unconfirmed\", reason: \"writer-active\" };\n\n return Effect.void;\n }),\n recordSession: (attempt, session) => {\n const record = attempts.get(attempt.attemptId);\n\n if (\n record === undefined ||\n record.attempt !== attempt ||\n session.projectId !== owned.projectId ||\n (record.session !== undefined && record.session.sessionId !== session.sessionId)\n ) {\n unknown();\n\n return;\n }\n // Retain identity even when cancellation/quarantine races a late allocation reply.\n record.session = Object.freeze(session);\n },\n rejected: (attempt) => {\n const record = attempts.get(attempt.attemptId);\n\n if (record === undefined || record.attempt !== attempt || record.session !== undefined) {\n unknown();\n\n return;\n }\n record.state = \"rejected\";\n if ([...attempts.values()].every((item) => item.state === \"rejected\"))\n persistence = { _tag: \"NotRequested\" };\n },\n uncertain: (attempt) => {\n const record = attempts.get(attempt.attemptId);\n\n if (record !== undefined && record.attempt === attempt) record.state = \"unknown\";\n unknown();\n },\n completed: (attempt, cleanup) => {\n const record = attempts.get(attempt.attemptId);\n\n if (\n record === undefined ||\n record.attempt !== attempt ||\n cleanup.ownership !== \"owned\" ||\n record.session === undefined ||\n record.session.sessionId !== cleanup.reference.sessionId ||\n cleanup.reference.projectId !== owned.projectId\n ) {\n unknown();\n\n return;\n }\n record.cleanup = cleanup;\n if (cleanup.remote !== \"confirmed\") {\n record.state = \"unknown\";\n unknown();\n\n return;\n }\n record.state = \"terminal\";\n if (cleanup.observedStatus !== \"COMPLETED\") {\n unknown();\n\n return;\n }\n if (!quarantined) persistence = { _tag: \"Unconfirmed\", reason: \"flush-unacknowledged\" };\n },\n confirmReadback: (atMillis) =>\n Effect.suspend(() => {\n if (\n closed ||\n quarantined ||\n !noActive() ||\n !Number.isFinite(atMillis) ||\n attempts.size === 0 ||\n [...attempts.values()].some(\n (entry) =>\n entry.state === \"terminal\" && entry.cleanup?.observedStatus !== \"COMPLETED\",\n )\n ) {\n return Effect.fail(\n ContextError.make({\n operation: \"writer-readback\",\n reason: \"active\",\n outcome: \"undispatched\",\n }),\n );\n }\n persistence = {\n _tag: \"Observed\",\n method: \"consumer-readback\",\n observedAtMillis: atMillis,\n };\n\n return Effect.void;\n }),\n quarantine: Effect.sync(unknown),\n snapshot: Effect.sync(() =>\n WriterSettlementFacts.make({\n reference: owned,\n attempts: [...attempts.values()].map((entry) =>\n WriterAttemptFacts.make({\n attempt: entry.attempt,\n state: entry.state,\n ...(entry.session === undefined ? {} : { session: entry.session }),\n ...(entry.cleanup === undefined ? {} : { cleanup: entry.cleanup }),\n }),\n ),\n persistence,\n disposition:\n quarantined || !noActive() || persistence._tag === \"Unconfirmed\"\n ? \"quarantine\"\n : \"release\",\n }),\n ),\n };\n\n Object.freeze(permit);\n authentic.set(permit, permit);\n active.set(key(owned), permit);\n // Explicit retirement closes admission without losing evidence attached to escaped permits.\n retirement.set(permit, (released) => {\n closed = true;\n if (active.get(key(owned)) !== permit) return;\n if (released) active.delete(key(owned));\n else active.set(key(owned), { _tag: \"Quarantined\", permit });\n });\n\n return Effect.succeed(permit);\n });\n\nconst retirement = new WeakMap<ContextWriterPermitInternal, (released: boolean) => void>();\n\nexport const closeContextWriterPermit = (\n permit: ContextWriterPermitInternal,\n released: boolean,\n): void => retirement.get(permit)?.(released);\n\nexport interface ReconciliationClaim {\n /** What the quarantined writer has recorded by now; empty when this process holds no quarantine. */\n readonly attempts: Effect.Effect<ReadonlyArray<WriterAttemptFacts>>;\n /** Lifts the quarantine, or puts it back when reconciliation did not succeed. */\n readonly finish: (reconciled: boolean) => void;\n}\n\nexport const claimReconciliation = (\n reference: ContextReference,\n): Effect.Effect<ReconciliationClaim, ContextError> =>\n Effect.suspend(() => {\n const held = active.get(key(reference));\n\n if (\n held?._tag === \"ContextWriterPermit\" ||\n held?._tag === \"Reconciling\" ||\n (held === undefined && active.size >= 2048)\n ) {\n return Effect.fail(\n ContextError.make({\n operation: \"writer-reconcile\",\n reason: \"active\",\n outcome: \"undispatched\",\n }),\n );\n }\n const claim: Reconciliation = { _tag: \"Reconciling\" };\n\n active.set(key(reference), claim);\n\n return Effect.succeed({\n attempts:\n held === undefined\n ? Effect.succeed([])\n : held.permit.snapshot.pipe(Effect.map((facts) => facts.attempts)),\n finish: (reconciled) => {\n if (active.get(key(reference)) !== claim) return;\n if (reconciled || held === undefined) active.delete(key(reference));\n else active.set(key(reference), held);\n },\n });\n });\n\nexport const requireContextWriterPermit = (\n permit: ContextWriterPermit,\n reference: ContextReference,\n): Effect.Effect<ContextWriterPermitInternal, ContextError> =>\n Effect.suspend(() => {\n const actual = authentic.get(permit);\n\n return actual !== undefined &&\n active.get(key(reference)) === actual &&\n actual.reference.contextId === reference.contextId &&\n actual.reference.projectId === reference.projectId\n ? Effect.succeed(actual)\n : Effect.fail(\n ContextError.make({\n operation: \"writer-authority\",\n reason: \"authorization\",\n outcome: \"undispatched\",\n }),\n );\n });\n"],"mappings":"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"}
package/dist/Contexts.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ContextReference, Identifier } from "./References.mjs";
2
2
  import { ContextError } from "./Errors.mjs";
3
3
  import { t as BrowserbaseClient } from "./Client-4RMKIpL2.mjs";
4
- import { n as isContextWriterBusy } from "./ContextWriter-oKWFLHuP.mjs";
4
+ import { r as isContextWriterBusy } from "./ContextWriter-CiEma24z.mjs";
5
5
  import { Context, Effect, Layer, Schema } from "effect";
6
6
  //#region src/Contexts.ts
7
7
  const Timestamp = Schema.String.check(Schema.isMaxLength(64));
package/dist/Errors.d.mts CHANGED
@@ -19,7 +19,7 @@ declare const SessionError_base: Schema.Class<SessionError, Schema.TaggedStruct<
19
19
  }>, import("effect/Cause").YieldableError>;
20
20
  export declare class SessionError extends SessionError_base {}
21
21
  declare const ContextError_base: Schema.Class<ContextError, Schema.TaggedStruct<"ContextError", {
22
- operation: Schema.Literals<readonly ["context-create", "context-retrieve", "context-delete", "writer", "writer-admit", "writer-authority", "writer-readback", "writer-settle"]>;
22
+ operation: Schema.Literals<readonly ["context-create", "context-retrieve", "context-delete", "writer", "writer-admit", "writer-authority", "writer-readback", "writer-settle", "writer-reconcile"]>;
23
23
  reason: Schema.Literals<readonly ["configuration", "authorization", "rate-limited", "not-found", "active", "disabled", "expired", "provider", "transport", "timeout", "malformed", "limit", "unsafe-url", "content-type"]>;
24
24
  outcome: Schema.optionalKey<Schema.Literals<readonly ["undispatched", "rejected", "unknown"]>>;
25
25
  status: Schema.optionalKey<Schema.Int>;
package/dist/Errors.mjs CHANGED
@@ -58,7 +58,8 @@ var ContextError = class extends Schema.TaggedError()("ContextError", requestFie
58
58
  "writer-admit",
59
59
  "writer-authority",
60
60
  "writer-readback",
61
- "writer-settle"
61
+ "writer-settle",
62
+ "writer-reconcile"
62
63
  ])) {};
63
64
  /**
64
65
  * `extension-archive` is the local inspection of the bytes a caller supplied, before any
@@ -1 +1 @@
1
- {"version":3,"file":"Errors.mjs","names":[],"sources":["../src/Errors.ts"],"sourcesContent":["import { Schema } from \"effect\";\n\nimport { AllocationAttempt, SessionReference } from \"./References.ts\";\n\nconst RequestReason = Schema.Literals([\n \"configuration\",\n \"authorization\",\n \"rate-limited\",\n \"not-found\",\n \"active\",\n \"disabled\",\n \"expired\",\n \"provider\",\n \"transport\",\n \"timeout\",\n \"malformed\",\n \"limit\",\n \"unsafe-url\",\n \"content-type\",\n]);\n\n/**\n * Every control-plane error shares these fields, but never a vocabulary: each names only the\n * operations its own service performs, so a caller can match on them exhaustively.\n */\nconst requestFields = <const Operations extends ReadonlyArray<string>>(operations: Operations) => ({\n operation: Schema.Literals(operations),\n reason: RequestReason,\n outcome: Schema.optionalKey(Schema.Literals([\"undispatched\", \"rejected\", \"unknown\"])),\n status: Schema.optionalKey(Schema.Int),\n retryAfterMillis: Schema.optionalKey(Schema.Natural),\n});\n\n/** Credential-free control-plane failures; response bodies and native causes never escape. */\nexport class ClientError extends Schema.TaggedError<ClientError>()(\n \"ClientError\",\n requestFields([\n \"configure\",\n \"provider-read\",\n \"provider-mutation\",\n \"provider-upload\",\n \"media-download\",\n ]),\n) {}\n\nexport class SessionError extends Schema.TaggedError<SessionError>()(\n \"SessionError\",\n requestFields([\n \"session-retrieve\",\n \"session-list\",\n \"session-release\",\n \"session-wait\",\n \"session-logs\",\n \"session-live-view\",\n \"session-connect\",\n \"session-attach\",\n ]),\n) {}\n\nexport class ContextError extends Schema.TaggedError<ContextError>()(\n \"ContextError\",\n requestFields([\n \"context-create\",\n \"context-retrieve\",\n \"context-delete\",\n \"writer\",\n \"writer-admit\",\n \"writer-authority\",\n \"writer-readback\",\n \"writer-settle\",\n ]),\n) {}\n\n/**\n * `extension-archive` is the local inspection of the bytes a caller supplied, before any\n * request. Why an archive was refused is its reason, never a second operation.\n */\nexport class ExtensionError extends Schema.TaggedError<ExtensionError>()(\"ExtensionError\", {\n ...requestFields([\n \"extension-archive\",\n \"extension-register\",\n \"extension-retrieve\",\n \"extension-delete\",\n ]),\n reason: Schema.Literals([...RequestReason.literals, \"unsafe-filename\"]),\n}) {}\n\n/** Project inspection and usage. */\nexport class ProjectError extends Schema.TaggedError<ProjectError>()(\n \"ProjectError\",\n requestFields([\"project-list\", \"project-retrieve\", \"project-usage\"]),\n) {}\n\n/** Proxy CA certificate administration. */\nexport class CertificateError extends Schema.TaggedError<CertificateError>()(\n \"CertificateError\",\n requestFields([\n \"certificate-create\",\n \"certificate-list\",\n \"certificate-retrieve\",\n \"certificate-delete\",\n ]),\n) {}\n\n/**\n * Browserbase platform services outside a browser session: Search, Fetch, Agents, Functions\n * and Webhooks. `service` names which one; these are host APIs, never model-facing tools.\n */\nexport class PlatformError extends Schema.TaggedError<PlatformError>()(\"PlatformError\", {\n ...requestFields([\n \"search-web\",\n \"fetch\",\n \"agent-create\",\n \"agent-list\",\n \"agent-retrieve\",\n \"agent-update\",\n \"agent-delete\",\n \"agent-run\",\n \"agent-run-list\",\n \"agent-run-retrieve\",\n \"agent-run-messages\",\n \"agent-run-stop\",\n \"agent-run-wait\",\n \"function-list\",\n \"function-retrieve\",\n \"function-versions\",\n \"function-version\",\n \"function-builds\",\n \"function-build\",\n \"function-build-logs\",\n \"function-invoke\",\n \"function-invocations\",\n \"function-invocation\",\n \"function-invocation-logs\",\n \"function-wait\",\n \"webhook-create\",\n \"webhook-list\",\n \"webhook-retrieve\",\n \"webhook-update\",\n \"webhook-delete\",\n \"webhook-rotate-secret\",\n ]),\n service: Schema.Literals([\"search\", \"fetch\", \"agents\", \"functions\", \"webhooks\"]),\n}) {}\n\nexport class FileError extends Schema.TaggedError<FileError>()(\"FileError\", {\n ...requestFields([\n \"upload\",\n \"downloads-list\",\n \"download-metadata\",\n \"download\",\n \"download-wait\",\n \"download-delete\",\n ]),\n reason: Schema.Literals([\n ...RequestReason.literals,\n \"unsafe-filename\",\n \"ambiguous\",\n \"checksum\",\n \"unsupported\",\n ]),\n}) {}\n\nexport class ArtifactError extends Schema.TaggedError<ArtifactError>()(\"ArtifactError\", {\n ...requestFields([\n \"recording-request\",\n \"recording-status\",\n \"recording-wait\",\n \"recording\",\n \"recording-download\",\n \"replay-metadata\",\n \"replay\",\n \"replay-playlist\",\n \"replay-media\",\n ]),\n reason: Schema.Literals([\n ...RequestReason.literals,\n \"failed\",\n \"byos\",\n \"assembly-unknown\",\n \"unsupported\",\n \"ambiguous\",\n ]),\n}) {}\n\n/** Creation has a known rejection or an uncertain effect; absence of a reply is not a rejection. */\nexport class AllocationError extends Schema.TaggedError<AllocationError>()(\"AllocationError\", {\n attempt: AllocationAttempt,\n reference: Schema.optionalKey(SessionReference),\n outcome: Schema.Literals([\"rejected\", \"unknown\"]),\n reason: Schema.Literals([\n \"authorization\",\n \"rate-limited\",\n \"configuration\",\n \"provider\",\n \"transport\",\n \"timeout\",\n \"malformed\",\n ]),\n status: Schema.optionalKey(Schema.Int),\n retryAfterMillis: Schema.optionalKey(Schema.Natural),\n}) {}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Errors.mjs","names":[],"sources":["../src/Errors.ts"],"sourcesContent":["import { Schema } from \"effect\";\n\nimport { AllocationAttempt, SessionReference } from \"./References.ts\";\n\nconst RequestReason = Schema.Literals([\n \"configuration\",\n \"authorization\",\n \"rate-limited\",\n \"not-found\",\n \"active\",\n \"disabled\",\n \"expired\",\n \"provider\",\n \"transport\",\n \"timeout\",\n \"malformed\",\n \"limit\",\n \"unsafe-url\",\n \"content-type\",\n]);\n\n/**\n * Every control-plane error shares these fields, but never a vocabulary: each names only the\n * operations its own service performs, so a caller can match on them exhaustively.\n */\nconst requestFields = <const Operations extends ReadonlyArray<string>>(operations: Operations) => ({\n operation: Schema.Literals(operations),\n reason: RequestReason,\n outcome: Schema.optionalKey(Schema.Literals([\"undispatched\", \"rejected\", \"unknown\"])),\n status: Schema.optionalKey(Schema.Int),\n retryAfterMillis: Schema.optionalKey(Schema.Natural),\n});\n\n/** Credential-free control-plane failures; response bodies and native causes never escape. */\nexport class ClientError extends Schema.TaggedError<ClientError>()(\n \"ClientError\",\n requestFields([\n \"configure\",\n \"provider-read\",\n \"provider-mutation\",\n \"provider-upload\",\n \"media-download\",\n ]),\n) {}\n\nexport class SessionError extends Schema.TaggedError<SessionError>()(\n \"SessionError\",\n requestFields([\n \"session-retrieve\",\n \"session-list\",\n \"session-release\",\n \"session-wait\",\n \"session-logs\",\n \"session-live-view\",\n \"session-connect\",\n \"session-attach\",\n ]),\n) {}\n\nexport class ContextError extends Schema.TaggedError<ContextError>()(\n \"ContextError\",\n requestFields([\n \"context-create\",\n \"context-retrieve\",\n \"context-delete\",\n \"writer\",\n \"writer-admit\",\n \"writer-authority\",\n \"writer-readback\",\n \"writer-settle\",\n \"writer-reconcile\",\n ]),\n) {}\n\n/**\n * `extension-archive` is the local inspection of the bytes a caller supplied, before any\n * request. Why an archive was refused is its reason, never a second operation.\n */\nexport class ExtensionError extends Schema.TaggedError<ExtensionError>()(\"ExtensionError\", {\n ...requestFields([\n \"extension-archive\",\n \"extension-register\",\n \"extension-retrieve\",\n \"extension-delete\",\n ]),\n reason: Schema.Literals([...RequestReason.literals, \"unsafe-filename\"]),\n}) {}\n\n/** Project inspection and usage. */\nexport class ProjectError extends Schema.TaggedError<ProjectError>()(\n \"ProjectError\",\n requestFields([\"project-list\", \"project-retrieve\", \"project-usage\"]),\n) {}\n\n/** Proxy CA certificate administration. */\nexport class CertificateError extends Schema.TaggedError<CertificateError>()(\n \"CertificateError\",\n requestFields([\n \"certificate-create\",\n \"certificate-list\",\n \"certificate-retrieve\",\n \"certificate-delete\",\n ]),\n) {}\n\n/**\n * Browserbase platform services outside a browser session: Search, Fetch, Agents, Functions\n * and Webhooks. `service` names which one; these are host APIs, never model-facing tools.\n */\nexport class PlatformError extends Schema.TaggedError<PlatformError>()(\"PlatformError\", {\n ...requestFields([\n \"search-web\",\n \"fetch\",\n \"agent-create\",\n \"agent-list\",\n \"agent-retrieve\",\n \"agent-update\",\n \"agent-delete\",\n \"agent-run\",\n \"agent-run-list\",\n \"agent-run-retrieve\",\n \"agent-run-messages\",\n \"agent-run-stop\",\n \"agent-run-wait\",\n \"function-list\",\n \"function-retrieve\",\n \"function-versions\",\n \"function-version\",\n \"function-builds\",\n \"function-build\",\n \"function-build-logs\",\n \"function-invoke\",\n \"function-invocations\",\n \"function-invocation\",\n \"function-invocation-logs\",\n \"function-wait\",\n \"webhook-create\",\n \"webhook-list\",\n \"webhook-retrieve\",\n \"webhook-update\",\n \"webhook-delete\",\n \"webhook-rotate-secret\",\n ]),\n service: Schema.Literals([\"search\", \"fetch\", \"agents\", \"functions\", \"webhooks\"]),\n}) {}\n\nexport class FileError extends Schema.TaggedError<FileError>()(\"FileError\", {\n ...requestFields([\n \"upload\",\n \"downloads-list\",\n \"download-metadata\",\n \"download\",\n \"download-wait\",\n \"download-delete\",\n ]),\n reason: Schema.Literals([\n ...RequestReason.literals,\n \"unsafe-filename\",\n \"ambiguous\",\n \"checksum\",\n \"unsupported\",\n ]),\n}) {}\n\nexport class ArtifactError extends Schema.TaggedError<ArtifactError>()(\"ArtifactError\", {\n ...requestFields([\n \"recording-request\",\n \"recording-status\",\n \"recording-wait\",\n \"recording\",\n \"recording-download\",\n \"replay-metadata\",\n \"replay\",\n \"replay-playlist\",\n \"replay-media\",\n ]),\n reason: Schema.Literals([\n ...RequestReason.literals,\n \"failed\",\n \"byos\",\n \"assembly-unknown\",\n \"unsupported\",\n \"ambiguous\",\n ]),\n}) {}\n\n/** Creation has a known rejection or an uncertain effect; absence of a reply is not a rejection. */\nexport class AllocationError extends Schema.TaggedError<AllocationError>()(\"AllocationError\", {\n attempt: AllocationAttempt,\n reference: Schema.optionalKey(SessionReference),\n outcome: Schema.Literals([\"rejected\", \"unknown\"]),\n reason: Schema.Literals([\n \"authorization\",\n \"rate-limited\",\n \"configuration\",\n \"provider\",\n \"transport\",\n \"timeout\",\n \"malformed\",\n ]),\n status: Schema.optionalKey(Schema.Int),\n retryAfterMillis: Schema.optionalKey(Schema.Natural),\n}) {}\n"],"mappings":"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"}
@@ -4,7 +4,7 @@ import { t as BrowserbaseClient } from "./Client-4RMKIpL2.mjs";
4
4
  import { t as resource } from "./Resource-DBksC4zB.mjs";
5
5
  import { ProxyRule } from "./Launch.mjs";
6
6
  import { n as proxy } from "./Launch-cAdE2rrZ.mjs";
7
- import { n as isContextWriterBusy } from "./ContextWriter-oKWFLHuP.mjs";
7
+ import { r as isContextWriterBusy } from "./ContextWriter-CiEma24z.mjs";
8
8
  import { Clock, Context, Effect, Layer, Schema } from "effect";
9
9
  //#region src/Functions.ts
10
10
  const Timestamp = Schema.String.check(Schema.isMaxLength(64));
package/dist/Testing.mjs CHANGED
@@ -4,7 +4,7 @@ import { recipe } from "./Launch.mjs";
4
4
  import { ProviderSession, SessionStatus } from "./SessionData.mjs";
5
5
  import { layer as layer$1 } from "./Account.mjs";
6
6
  import { layer as layer$2 } from "./BrowserBinding.mjs";
7
- import { t as BrowserbaseBrowser } from "./Browser-Dw0JFTaD.mjs";
7
+ import { t as BrowserbaseBrowser } from "./Browser-BPcF550A.mjs";
8
8
  import { Context, Effect, Layer, Redacted, Schema } from "effect";
9
9
  import { FetchHttpClient } from "effect/unstable/http";
10
10
  import * as BrowserTesting from "effect-browser/testing";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "effect-browserbase",
3
- "version": "0.2.0-beta.4",
3
+ "version": "0.2.0-beta.6",
4
4
  "description": "Effect-based Browserbase resources and hosted integration for effect-browser.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "peerDependencies": {
17
17
  "effect": "^4.0.0-rc.117",
18
- "effect-browser": "0.2.0-beta.4"
18
+ "effect-browser": "0.2.0-beta.6"
19
19
  },
20
20
  "homepage": "https://github.com/mannyc2/effect-agent-browserbase#readme",
21
21
  "bugs": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"ContextWriter-oKWFLHuP.mjs","names":[],"sources":["../src/internal/session/WriterFacts.ts","../src/internal/session/ContextWriter.ts"],"sourcesContent":["import { type Effect, Schema } from \"effect\";\n\nimport { CleanupResult } from \"../../Cleanup.ts\";\nimport { AllocationAttempt, ContextReference, SessionReference } from \"../../References.ts\";\n\n/**\n * The writer vocabulary both the public coordination entry point and the permit\n * implementation need. Keeping it here leaves one direction of dependency:\n * `ContextCoordination` and `ContextWriter` both read this module, never each other.\n */\nexport const PersistenceEvidence = Schema.Union([\n Schema.TaggedStruct(\"NotRequested\", {}),\n Schema.TaggedStruct(\"Unconfirmed\", {\n reason: Schema.Literals([\"writer-active\", \"writer-unknown\", \"flush-unacknowledged\"]),\n }),\n Schema.TaggedStruct(\"Observed\", {\n method: Schema.Literal(\"consumer-readback\"),\n observedAtMillis: Schema.Finite,\n }),\n]);\n\nexport type PersistenceEvidence = typeof PersistenceEvidence.Type;\n\nexport class WriterAttemptFacts extends Schema.Class<WriterAttemptFacts>(\n \"BrowserbaseWriterAttemptFacts\",\n)({\n attempt: AllocationAttempt,\n session: Schema.optionalKey(SessionReference),\n state: Schema.Literals([\"admitted\", \"rejected\", \"unknown\", \"terminal\"]),\n cleanup: Schema.optionalKey(CleanupResult),\n}) {}\n\nexport class WriterSettlementFacts extends Schema.Class<WriterSettlementFacts>(\n \"BrowserbaseWriterSettlementFacts\",\n)({\n reference: ContextReference,\n attempts: Schema.Array(WriterAttemptFacts).check(Schema.isMaxLength(64)),\n persistence: PersistenceEvidence,\n disposition: Schema.Literals([\"release\", \"quarantine\"]),\n}) {}\n\nexport interface WriterLease<E, R> {\n readonly settle: (facts: WriterSettlementFacts) => Effect.Effect<void, E, R>;\n}\n\nexport interface ContextWriterBackend<E, R> {\n readonly acquire: (reference: ContextReference) => Effect.Effect<WriterLease<E, R>, E, R>;\n}\n\nexport interface ContextWriterPermit {\n readonly _tag: \"ContextWriterPermit\";\n readonly reference: ContextReference;\n}\n\nexport interface WriterOptions<A, VerifyE, VerifyR> {\n /** Bounded consumer-controlled readback, not a provider-wide flush acknowledgement. */\n readonly verify?: (value: A) => Effect.Effect<void, VerifyE, VerifyR>;\n readonly settlementTimeoutMillis?: number;\n}\n","import { Effect } from \"effect\";\n\nimport type { CleanupResult } from \"../../Cleanup.ts\";\nimport { ContextError } from \"../../Errors.ts\";\nimport type { AllocationAttempt, ContextReference, SessionReference } from \"../../References.ts\";\nimport {\n type ContextWriterPermit,\n type PersistenceEvidence,\n WriterAttemptFacts,\n WriterSettlementFacts,\n} from \"./WriterFacts.ts\";\n\n/** There is one record per exact allocation attempt, not parallel uncorrelated arrays. */\ninterface AttemptRecord {\n readonly attempt: AllocationAttempt;\n session?: SessionReference;\n state: \"admitted\" | \"rejected\" | \"unknown\" | \"terminal\";\n cleanup?: CleanupResult;\n}\n\nexport interface ContextWriterPermitInternal extends ContextWriterPermit {\n readonly recordAttempt: (attempt: AllocationAttempt) => Effect.Effect<void, ContextError>;\n readonly recordSession: (attempt: AllocationAttempt, reference: SessionReference) => void;\n readonly rejected: (attempt: AllocationAttempt) => void;\n readonly uncertain: (attempt: AllocationAttempt) => void;\n readonly completed: (attempt: AllocationAttempt, cleanup: CleanupResult) => void;\n readonly confirmReadback: (atMillis: number) => Effect.Effect<void, ContextError>;\n readonly quarantine: Effect.Effect<void>;\n readonly snapshot: Effect.Effect<WriterSettlementFacts>;\n}\n\nconst authentic = new WeakMap<ContextWriterPermit, ContextWriterPermitInternal>();\nconst active = new Map<string, ContextWriterPermitInternal | \"quarantined\">();\nconst key = (ref: ContextReference) => `${ref.projectId}/${ref.contextId}`;\n\nexport const isContextWriterBusy = (ref: ContextReference): boolean => active.has(key(ref));\n\nexport const makeContextWriterPermit = (\n reference: ContextReference,\n): Effect.Effect<ContextWriterPermitInternal, ContextError> =>\n Effect.suspend(() => {\n if (active.has(key(reference)) || active.size >= 2048)\n return Effect.fail(\n ContextError.make({ operation: \"writer\", reason: \"active\", outcome: \"undispatched\" }),\n );\n const owned = Object.freeze(reference);\n const attempts = new Map<string, AttemptRecord>();\n\n let closed = false,\n quarantined = false;\n\n let persistence: PersistenceEvidence = { _tag: \"NotRequested\" };\n\n const unknown = () => {\n quarantined = true;\n persistence = { _tag: \"Unconfirmed\", reason: \"writer-unknown\" };\n };\n\n const noActive = () =>\n [...attempts.values()].every(\n (entry) => entry.state === \"rejected\" || entry.state === \"terminal\",\n );\n\n const permit: ContextWriterPermitInternal = {\n _tag: \"ContextWriterPermit\",\n reference: owned,\n recordAttempt: (attempt) =>\n Effect.suspend(() => {\n if (\n closed ||\n quarantined ||\n !noActive() ||\n attempt.projectId !== owned.projectId ||\n (attempts.size > 0 && persistence._tag === \"Unconfirmed\")\n ) {\n return Effect.fail(\n ContextError.make({\n operation: \"writer-admit\",\n reason: \"active\",\n outcome: \"undispatched\",\n }),\n );\n }\n if (attempts.has(attempt.attemptId) || attempts.size >= 64)\n return Effect.fail(\n ContextError.make({\n operation: \"writer-admit\",\n reason: \"limit\",\n outcome: \"undispatched\",\n }),\n );\n const copy = Object.freeze(attempt);\n\n attempts.set(copy.attemptId, { attempt: copy, state: \"admitted\" });\n persistence = { _tag: \"Unconfirmed\", reason: \"writer-active\" };\n\n return Effect.void;\n }),\n recordSession: (attempt, session) => {\n const record = attempts.get(attempt.attemptId);\n\n if (\n record === undefined ||\n record.attempt !== attempt ||\n session.projectId !== owned.projectId ||\n (record.session !== undefined && record.session.sessionId !== session.sessionId)\n ) {\n unknown();\n\n return;\n }\n // Retain identity even when cancellation/quarantine races a late allocation reply.\n record.session = Object.freeze(session);\n },\n rejected: (attempt) => {\n const record = attempts.get(attempt.attemptId);\n\n if (record === undefined || record.attempt !== attempt || record.session !== undefined) {\n unknown();\n\n return;\n }\n record.state = \"rejected\";\n if ([...attempts.values()].every((item) => item.state === \"rejected\"))\n persistence = { _tag: \"NotRequested\" };\n },\n uncertain: (attempt) => {\n const record = attempts.get(attempt.attemptId);\n\n if (record !== undefined && record.attempt === attempt) record.state = \"unknown\";\n unknown();\n },\n completed: (attempt, cleanup) => {\n const record = attempts.get(attempt.attemptId);\n\n if (\n record === undefined ||\n record.attempt !== attempt ||\n cleanup.ownership !== \"owned\" ||\n record.session === undefined ||\n record.session.sessionId !== cleanup.reference.sessionId ||\n cleanup.reference.projectId !== owned.projectId\n ) {\n unknown();\n\n return;\n }\n record.cleanup = cleanup;\n if (cleanup.remote !== \"confirmed\") {\n record.state = \"unknown\";\n unknown();\n\n return;\n }\n record.state = \"terminal\";\n if (cleanup.observedStatus !== \"COMPLETED\") {\n unknown();\n\n return;\n }\n if (!quarantined) persistence = { _tag: \"Unconfirmed\", reason: \"flush-unacknowledged\" };\n },\n confirmReadback: (atMillis) =>\n Effect.suspend(() => {\n if (\n closed ||\n quarantined ||\n !noActive() ||\n !Number.isFinite(atMillis) ||\n attempts.size === 0 ||\n [...attempts.values()].some(\n (entry) =>\n entry.state === \"terminal\" && entry.cleanup?.observedStatus !== \"COMPLETED\",\n )\n ) {\n return Effect.fail(\n ContextError.make({\n operation: \"writer-readback\",\n reason: \"active\",\n outcome: \"undispatched\",\n }),\n );\n }\n persistence = {\n _tag: \"Observed\",\n method: \"consumer-readback\",\n observedAtMillis: atMillis,\n };\n\n return Effect.void;\n }),\n quarantine: Effect.sync(unknown),\n snapshot: Effect.sync(() =>\n WriterSettlementFacts.make({\n reference: owned,\n attempts: [...attempts.values()].map((entry) =>\n WriterAttemptFacts.make({\n attempt: entry.attempt,\n state: entry.state,\n ...(entry.session === undefined ? {} : { session: entry.session }),\n ...(entry.cleanup === undefined ? {} : { cleanup: entry.cleanup }),\n }),\n ),\n persistence,\n disposition:\n quarantined || !noActive() || persistence._tag === \"Unconfirmed\"\n ? \"quarantine\"\n : \"release\",\n }),\n ),\n };\n\n Object.freeze(permit);\n authentic.set(permit, permit);\n active.set(key(owned), permit);\n // Explicit retirement closes admission without losing evidence attached to escaped permits.\n retirement.set(permit, (released) => {\n closed = true;\n if (active.get(key(owned)) !== permit) return;\n if (released) active.delete(key(owned));\n else active.set(key(owned), \"quarantined\");\n });\n\n return Effect.succeed(permit);\n });\n\nconst retirement = new WeakMap<ContextWriterPermitInternal, (released: boolean) => void>();\n\nexport const closeContextWriterPermit = (\n permit: ContextWriterPermitInternal,\n released: boolean,\n): void => retirement.get(permit)?.(released);\n\nexport const requireContextWriterPermit = (\n permit: ContextWriterPermit,\n reference: ContextReference,\n): Effect.Effect<ContextWriterPermitInternal, ContextError> =>\n Effect.suspend(() => {\n const actual = authentic.get(permit);\n\n return actual !== undefined &&\n active.get(key(reference)) === actual &&\n actual.reference.contextId === reference.contextId &&\n actual.reference.projectId === reference.projectId\n ? Effect.succeed(actual)\n : Effect.fail(\n ContextError.make({\n operation: \"writer-authority\",\n reason: \"authorization\",\n outcome: \"undispatched\",\n }),\n );\n });\n"],"mappings":"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"}