effect-browserbase 0.2.0-beta.6 → 0.2.0-beta.8
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 +35 -21
- package/dist/Account.mjs +3 -3
- package/dist/{Acquisition-Ca4EE-Fg.mjs → Acquisition-BOABu_qJ.mjs} +21 -12
- package/dist/Acquisition-BOABu_qJ.mjs.map +1 -0
- package/dist/Agents.mjs +25 -25
- package/dist/Agents.mjs.map +1 -1
- package/dist/Allocation.mjs +1 -1
- package/dist/{Browser-BPcF550A.mjs → Browser-ByrWJ0ss.mjs} +21 -17
- package/dist/Browser-ByrWJ0ss.mjs.map +1 -0
- package/dist/Browser.d.mts +11 -9
- package/dist/Browser.mjs +1 -1
- package/dist/Certificates.mjs +9 -9
- package/dist/Certificates.mjs.map +1 -1
- package/dist/{Client-4RMKIpL2.mjs → Client-BEC4Q8ZS.mjs} +154 -14
- package/dist/Client-BEC4Q8ZS.mjs.map +1 -0
- package/dist/Client.mjs +1 -1
- package/dist/ContextCoordination.mjs +9 -8
- package/dist/ContextCoordination.mjs.map +1 -1
- package/dist/Contexts.mjs +7 -7
- package/dist/Contexts.mjs.map +1 -1
- package/dist/Downloads.mjs +10 -10
- package/dist/Downloads.mjs.map +1 -1
- package/dist/{Extensions-Dg3jHOf0.mjs → Extensions-BTUn9zhK.mjs} +8 -8
- package/dist/Extensions-BTUn9zhK.mjs.map +1 -0
- package/dist/Extensions.mjs +1 -1
- package/dist/Functions.mjs +27 -27
- package/dist/Functions.mjs.map +1 -1
- package/dist/PageFetch.mjs +4 -4
- package/dist/PageFetch.mjs.map +1 -1
- package/dist/Projects.mjs +5 -5
- package/dist/Projects.mjs.map +1 -1
- package/dist/Recordings.mjs +42 -27
- package/dist/Recordings.mjs.map +1 -1
- package/dist/Replays.mjs +6 -6
- package/dist/Replays.mjs.map +1 -1
- package/dist/{Resource-DBksC4zB.mjs → Resource-J7Kkk5mu.mjs} +7 -3
- package/dist/Resource-J7Kkk5mu.mjs.map +1 -0
- package/dist/Search.mjs +4 -4
- package/dist/Search.mjs.map +1 -1
- package/dist/{Sessions-BUoyPcPJ.mjs → Sessions-D2H5m6rF.mjs} +15 -15
- package/dist/Sessions-D2H5m6rF.mjs.map +1 -0
- package/dist/Sessions.mjs +1 -1
- package/dist/Testing.mjs +1 -1
- package/dist/Uploads.mjs +4 -4
- package/dist/Uploads.mjs.map +1 -1
- package/dist/Webhooks.mjs +14 -14
- package/dist/Webhooks.mjs.map +1 -1
- package/package.json +2 -2
- package/dist/Acquisition-Ca4EE-Fg.mjs.map +0 -1
- package/dist/Browser-BPcF550A.mjs.map +0 -1
- package/dist/Client-4RMKIpL2.mjs.map +0 -1
- package/dist/Extensions-Dg3jHOf0.mjs.map +0 -1
- package/dist/Resource-DBksC4zB.mjs.map +0 -1
- package/dist/Sessions-BUoyPcPJ.mjs.map +0 -1
package/dist/Recordings.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Recordings.mjs","names":[],"sources":["../src/Recordings.ts"],"sourcesContent":["import { Context, Effect, Layer, Redacted, Schema, Semaphore, Stream } from \"effect\";\n\nimport { BrowserbaseClient } from \"./Client.ts\";\nimport { ArtifactError, type ClientError } from \"./Errors.ts\";\nimport { requireTerminalSession } from \"./internal/artifact/Authorization.ts\";\nimport { transferPolicy } from \"./internal/artifact/TransferPolicy.ts\";\nimport { deadlineAfter, nowMillis, until } from \"./internal/Deadline.ts\";\nimport { Identifier, type SessionReference } from \"./References.ts\";\nimport { BrowserbaseSessions } from \"./Sessions.ts\";\nimport {\n type ArtifactTransferPolicy,\n RecordingBatch,\n RecordingPage,\n RecordingPageReference,\n} from \"./Transfers.ts\";\n\nconst RawPage = Schema.Struct({\n pageId: Identifier,\n status: Schema.Literals([\"NOT_REQUESTED\", \"PENDING\", \"COMPLETED\", \"FAILED\"]),\n completedAt: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(64))),\n downloadUrl: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(16384))),\n});\n\nconst RawBatch = Schema.Struct({ downloads: Schema.Array(RawPage).check(Schema.isMaxLength(256)) });\n\nexport interface PollOptions {\n readonly timeoutMillis?: number;\n readonly intervalMillis?: number;\n}\n\n/** Recording transfers share the canonical artifact bounds. */\nexport type DownloadLimits = ArtifactTransferPolicy;\n\nconst failure = (operation: ArtifactError[\"operation\"], reason: ArtifactError[\"reason\"]) =>\n ArtifactError.make({ operation, reason });\n\nconst fromClient = (operation: ArtifactError[\"operation\"]) => (error: ClientError) =>\n ArtifactError.make({\n operation,\n reason: error.reason,\n ...(error.outcome === undefined ? {} : { outcome: error.outcome }),\n ...(error.status === undefined ? {} : { status: error.status }),\n ...(error.retryAfterMillis === undefined ? {} : { retryAfterMillis: error.retryAfterMillis }),\n });\n\nconst within = <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n deadline: number,\n operation: ArtifactError[\"operation\"],\n) => until(effect, deadline, () => failure(operation, \"timeout\"));\n\n/** Independent of a live browser. Merely building this Layer performs no provider calls. */\nexport class BrowserbaseRecordings extends Context.Service<\n BrowserbaseRecordings,\n {\n readonly request: (\n reference: SessionReference,\n mode?: \"initial\" | \"retry-failed\",\n ) => Effect.Effect<RecordingBatch, ArtifactError>;\n readonly status: (reference: SessionReference) => Effect.Effect<RecordingBatch, ArtifactError>;\n readonly wait: (\n reference: SessionReference,\n options?: PollOptions,\n ) => Effect.Effect<RecordingBatch, ArtifactError>;\n readonly download: (\n reference: RecordingPageReference,\n limits: DownloadLimits,\n ) => Stream.Stream<Uint8Array, ArtifactError>;\n }\n>()(\"effect-browserbase/Recordings\") {\n static readonly layer: Layer.Layer<\n BrowserbaseRecordings,\n never,\n BrowserbaseClient | BrowserbaseSessions\n > = Layer.effect(\n BrowserbaseRecordings,\n Effect.gen(function* () {\n const client = yield* BrowserbaseClient;\n const sessions = yield* BrowserbaseSessions;\n const requests = yield* Semaphore.make(1);\n\n const path = (ref: SessionReference) =>\n `/v1/sessions/${encodeURIComponent(ref.sessionId)}/recording/downloads`;\n\n const read = (ref: SessionReference, deadline?: number) =>\n client.json(\"GET\", path(ref), undefined, deadline).pipe(\n Effect.mapError(fromClient(\"recording-status\")),\n Effect.flatMap((raw) =>\n Schema.decodeUnknownEffect(RawBatch)(raw).pipe(\n Effect.mapError(() => failure(\"recording-status\", \"malformed\")),\n ),\n ),\n Effect.filterOrFail(\n (raw) =>\n new Set(raw.downloads.map((page) => page.pageId)).size === raw.downloads.length,\n () => failure(\"recording-status\", \"malformed\"),\n ),\n );\n\n const project = (ref: SessionReference, raw: typeof RawBatch.Type, timedOut = false) =>\n RecordingBatch.make({\n reference: ref,\n timedOut,\n pages: raw.downloads.map((page) =>\n RecordingPage.make({\n pageId: page.pageId,\n status: page.status,\n delivery:\n page.status !== \"COMPLETED\"\n ? \"not-ready\"\n : page.downloadUrl === undefined\n ? \"external-storage\"\n : \"download\",\n ...(page.completedAt === undefined ? {} : { completedAt: page.completedAt }),\n }),\n ),\n });\n\n const authorize = (ref: SessionReference) =>\n requireTerminalSession(\n sessions,\n ref,\n () => failure(\"recording\", \"active\"),\n (error) => ArtifactError.make({ operation: \"recording\", reason: error.reason }),\n );\n\n const status = Effect.fnUntraced(function* (ref: SessionReference) {\n yield* authorize(ref);\n\n return project(ref, yield* read(ref));\n });\n\n const request = (ref: SessionReference, mode: \"initial\" | \"retry-failed\" = \"initial\") =>\n requests.withPermits(1)(\n Effect.gen(function* () {\n if (mode !== \"initial\" && mode !== \"retry-failed\")\n return yield* ArtifactError.make({\n operation: \"recording-request\",\n reason: \"configuration\",\n outcome: \"undispatched\",\n });\n yield* authorize(ref);\n // A prior uncertain POST is reconciled by this GET before any resubmission.\n const before = yield* read(ref);\n\n const needed =\n mode === \"retry-failed\"\n ? before.downloads.some((page) => page.status === \"FAILED\")\n : before.downloads.every((page) => page.status === \"NOT_REQUESTED\");\n\n if (!needed) return project(ref, before);\n\n const raw = yield* client.json(\"POST\", path(ref)).pipe(\n Effect.mapError((error) =>\n ArtifactError.make({\n operation: \"recording-request\",\n reason:\n error.status !== undefined && error.status >= 400 && error.status < 500\n ? error.reason\n : \"assembly-unknown\",\n outcome:\n error.status !== undefined && error.status >= 400 && error.status < 500\n ? \"rejected\"\n : \"unknown\",\n ...(error.status === undefined ? {} : { status: error.status }),\n ...(error.retryAfterMillis === undefined\n ? {}\n : { retryAfterMillis: error.retryAfterMillis }),\n }),\n ),\n Effect.flatMap((value) =>\n Schema.decodeUnknownEffect(RawBatch)(value).pipe(\n Effect.mapError(() =>\n ArtifactError.make({\n operation: \"recording-request\",\n reason: \"malformed\",\n outcome: \"unknown\",\n }),\n ),\n ),\n ),\n );\n\n return project(ref, raw);\n }),\n );\n\n const wait = Effect.fnUntraced(function* (ref: SessionReference, options: PollOptions = {}) {\n const timeout = options.timeoutMillis ?? 120_000;\n const interval = options.intervalMillis ?? 3000;\n\n if (\n !Number.isSafeInteger(timeout) ||\n timeout < 1 ||\n timeout > 600_000 ||\n !Number.isSafeInteger(interval) ||\n interval < 10 ||\n interval > 30_000\n ) {\n return yield* failure(\"recording-wait\", \"configuration\");\n }\n const deadline = yield* deadlineAfter(timeout);\n\n yield* within(authorize(ref), deadline, \"recording-wait\");\n let latest: typeof RawBatch.Type = { downloads: [] };\n\n for (;;) {\n const result = yield* within(read(ref, deadline), deadline, \"recording-wait\").pipe(\n Effect.result,\n );\n\n if (result._tag === \"Success\") {\n latest = result.success;\n if (\n latest.downloads.every(\n (page) => page.status === \"COMPLETED\" || page.status === \"FAILED\",\n )\n )\n return project(ref, latest);\n } else if (\n ![\"timeout\", \"rate-limited\", \"provider\", \"transport\"].includes(result.failure.reason)\n ) {\n return yield* result.failure;\n }\n const remaining = deadline - (yield* nowMillis);\n\n if (remaining <= 0) return project(ref, latest, true);\n yield* Effect.sleep(Math.min(interval, remaining));\n }\n });\n\n const download = (ref: RecordingPageReference, limits: DownloadLimits) =>\n Stream.unwrap(\n Effect.gen(function* () {\n yield* Schema.decodeEffect(RecordingPageReference)(ref).pipe(\n Effect.mapError(() => failure(\"recording-download\", \"configuration\")),\n );\n\n const { maxBytes, timeoutMillis } = yield* transferPolicy(limits, () =>\n failure(\"recording-download\", \"configuration\"),\n );\n\n const deadline = yield* deadlineAfter(timeoutMillis);\n\n yield* within(authorize(ref.session), deadline, \"recording-download\");\n\n const latest = yield* within(\n read(ref.session, deadline),\n deadline,\n \"recording-download\",\n );\n\n const page = latest.downloads.find((entry) => entry.pageId === ref.pageId);\n\n if (page === undefined) return yield* failure(\"recording-download\", \"not-found\");\n if (page.status === \"FAILED\") return yield* failure(\"recording-download\", \"failed\");\n if (page.status !== \"COMPLETED\") return yield* failure(\"recording-download\", \"active\");\n if (page.downloadUrl === undefined) return yield* failure(\"recording-download\", \"byos\");\n\n // A fresh GET mints access for this subscription. No URL is persisted in the reference.\n return client\n .media(\n Redacted.make(page.downloadUrl),\n maxBytes,\n [\"video/mp4\", \"application/octet-stream\"],\n timeoutMillis,\n deadline,\n )\n .pipe(Stream.mapError(fromClient(\"recording-download\")));\n }),\n );\n\n return BrowserbaseRecordings.of({ request, status, wait, download });\n }),\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Recordings.mjs","names":["Trace.span","Trace.annotate","Trace.stream"],"sources":["../src/Recordings.ts"],"sourcesContent":["import { Context, Effect, Layer, Redacted, Schema, Semaphore, Stream } from \"effect\";\n\nimport { BrowserbaseClient } from \"./Client.ts\";\nimport { ArtifactError, type ClientError } from \"./Errors.ts\";\nimport { requireTerminalSession } from \"./internal/artifact/Authorization.ts\";\nimport { transferPolicy } from \"./internal/artifact/TransferPolicy.ts\";\nimport { deadlineAfter, nowMillis, until } from \"./internal/Deadline.ts\";\nimport * as Trace from \"./internal/Trace.ts\";\nimport { Identifier, type SessionReference } from \"./References.ts\";\nimport { BrowserbaseSessions } from \"./Sessions.ts\";\nimport {\n type ArtifactTransferPolicy,\n RecordingBatch,\n RecordingPage,\n RecordingPageReference,\n} from \"./Transfers.ts\";\n\nconst RawPage = Schema.Struct({\n pageId: Identifier,\n status: Schema.Literals([\"NOT_REQUESTED\", \"PENDING\", \"COMPLETED\", \"FAILED\"]),\n completedAt: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(64))),\n downloadUrl: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(16384))),\n});\n\nconst RawBatch = Schema.Struct({ downloads: Schema.Array(RawPage).check(Schema.isMaxLength(256)) });\n\nexport interface PollOptions {\n readonly timeoutMillis?: number;\n readonly intervalMillis?: number;\n}\n\n/** Recording transfers share the canonical artifact bounds. */\nexport type DownloadLimits = ArtifactTransferPolicy;\n\nconst failure = (operation: ArtifactError[\"operation\"], reason: ArtifactError[\"reason\"]) =>\n ArtifactError.make({ operation, reason });\n\nconst fromClient = (operation: ArtifactError[\"operation\"]) => (error: ClientError) =>\n ArtifactError.make({\n operation,\n reason: error.reason,\n ...(error.outcome === undefined ? {} : { outcome: error.outcome }),\n ...(error.status === undefined ? {} : { status: error.status }),\n ...(error.retryAfterMillis === undefined ? {} : { retryAfterMillis: error.retryAfterMillis }),\n });\n\nconst within = <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n deadline: number,\n operation: ArtifactError[\"operation\"],\n) => until(effect, deadline, () => failure(operation, \"timeout\"));\n\n/** Independent of a live browser. Merely building this Layer performs no provider calls. */\nexport class BrowserbaseRecordings extends Context.Service<\n BrowserbaseRecordings,\n {\n readonly request: (\n reference: SessionReference,\n mode?: \"initial\" | \"retry-failed\",\n ) => Effect.Effect<RecordingBatch, ArtifactError>;\n readonly status: (reference: SessionReference) => Effect.Effect<RecordingBatch, ArtifactError>;\n readonly wait: (\n reference: SessionReference,\n options?: PollOptions,\n ) => Effect.Effect<RecordingBatch, ArtifactError>;\n readonly download: (\n reference: RecordingPageReference,\n limits: DownloadLimits,\n ) => Stream.Stream<Uint8Array, ArtifactError>;\n }\n>()(\"effect-browserbase/Recordings\") {\n static readonly layer: Layer.Layer<\n BrowserbaseRecordings,\n never,\n BrowserbaseClient | BrowserbaseSessions\n > = Layer.effect(\n BrowserbaseRecordings,\n Effect.gen(function* () {\n const client = yield* BrowserbaseClient;\n const sessions = yield* BrowserbaseSessions;\n const requests = yield* Semaphore.make(1);\n\n const path = (ref: SessionReference) =>\n `/v1/sessions/${encodeURIComponent(ref.sessionId)}/recording/downloads`;\n\n const read = (ref: SessionReference, deadline?: number) =>\n client.json(\"GET\", path(ref), undefined, deadline).pipe(\n Effect.mapError(fromClient(\"recording-status\")),\n Effect.flatMap((raw) =>\n Schema.decodeUnknownEffect(RawBatch)(raw).pipe(\n Effect.mapError(() => failure(\"recording-status\", \"malformed\")),\n ),\n ),\n Effect.filterOrFail(\n (raw) =>\n new Set(raw.downloads.map((page) => page.pageId)).size === raw.downloads.length,\n () => failure(\"recording-status\", \"malformed\"),\n ),\n );\n\n const project = (ref: SessionReference, raw: typeof RawBatch.Type, timedOut = false) =>\n RecordingBatch.make({\n reference: ref,\n timedOut,\n pages: raw.downloads.map((page) =>\n RecordingPage.make({\n pageId: page.pageId,\n status: page.status,\n delivery:\n page.status !== \"COMPLETED\"\n ? \"not-ready\"\n : page.downloadUrl === undefined\n ? \"external-storage\"\n : \"download\",\n ...(page.completedAt === undefined ? {} : { completedAt: page.completedAt }),\n }),\n ),\n });\n\n const authorize = (ref: SessionReference) =>\n requireTerminalSession(\n sessions,\n ref,\n () => failure(\"recording\", \"active\"),\n (error) => ArtifactError.make({ operation: \"recording\", reason: error.reason }),\n );\n\n const status = Effect.fnUntraced(function* (ref: SessionReference) {\n yield* authorize(ref);\n\n return project(ref, yield* read(ref));\n }, Trace.span(\"BrowserbaseRecordings.status\"));\n\n const request = (ref: SessionReference, mode: \"initial\" | \"retry-failed\" = \"initial\") =>\n requests\n .withPermits(1)(\n Effect.gen(function* () {\n if (mode !== \"initial\" && mode !== \"retry-failed\")\n return yield* ArtifactError.make({\n operation: \"recording-request\",\n reason: \"configuration\",\n outcome: \"undispatched\",\n });\n yield* authorize(ref);\n // A prior uncertain POST is reconciled by this GET before any resubmission.\n const before = yield* read(ref);\n\n const needed =\n mode === \"retry-failed\"\n ? before.downloads.some((page) => page.status === \"FAILED\")\n : before.downloads.every((page) => page.status === \"NOT_REQUESTED\");\n\n if (!needed) return project(ref, before);\n\n const raw = yield* client.json(\"POST\", path(ref)).pipe(\n Effect.mapError((error) =>\n ArtifactError.make({\n operation: \"recording-request\",\n reason:\n error.status !== undefined && error.status >= 400 && error.status < 500\n ? error.reason\n : \"assembly-unknown\",\n outcome:\n error.status !== undefined && error.status >= 400 && error.status < 500\n ? \"rejected\"\n : \"unknown\",\n ...(error.status === undefined ? {} : { status: error.status }),\n ...(error.retryAfterMillis === undefined\n ? {}\n : { retryAfterMillis: error.retryAfterMillis }),\n }),\n ),\n Effect.flatMap((value) =>\n Schema.decodeUnknownEffect(RawBatch)(value).pipe(\n Effect.mapError(() =>\n ArtifactError.make({\n operation: \"recording-request\",\n reason: \"malformed\",\n outcome: \"unknown\",\n }),\n ),\n ),\n ),\n );\n\n return project(ref, raw);\n }),\n )\n .pipe(Trace.span(\"BrowserbaseRecordings.request\"));\n\n const wait = (ref: SessionReference, options: PollOptions = {}) =>\n Effect.suspend(() => {\n let failedPolls = 0;\n let lastFailure: ArtifactError[\"reason\"] | undefined;\n let timedOut = false;\n\n return Effect.gen(function* () {\n const timeout = options.timeoutMillis ?? 120_000;\n const interval = options.intervalMillis ?? 3000;\n\n if (\n !Number.isSafeInteger(timeout) ||\n timeout < 1 ||\n timeout > 600_000 ||\n !Number.isSafeInteger(interval) ||\n interval < 10 ||\n interval > 30_000\n ) {\n return yield* failure(\"recording-wait\", \"configuration\");\n }\n const deadline = yield* deadlineAfter(timeout);\n\n yield* within(authorize(ref), deadline, \"recording-wait\").pipe(\n Effect.withTracerEnabled(false),\n );\n let latest: typeof RawBatch.Type = { downloads: [] };\n\n for (;;) {\n const result = yield* within(read(ref, deadline), deadline, \"recording-wait\").pipe(\n Effect.withTracerEnabled(false),\n Effect.tapError((error) =>\n Effect.sync(() => {\n failedPolls = Math.min(Number.MAX_SAFE_INTEGER, failedPolls + 1);\n lastFailure = error.reason;\n }),\n ),\n Effect.result,\n );\n\n if (result._tag === \"Success\") {\n latest = result.success;\n if (\n latest.downloads.every(\n (page) => page.status === \"COMPLETED\" || page.status === \"FAILED\",\n )\n )\n return project(ref, latest);\n } else if (\n ![\"timeout\", \"rate-limited\", \"provider\", \"transport\"].includes(\n result.failure.reason,\n )\n ) {\n return yield* result.failure;\n }\n const remaining = deadline - (yield* nowMillis);\n\n if (remaining <= 0) {\n timedOut = true;\n\n return project(ref, latest, true);\n }\n yield* Effect.sleep(Math.min(interval, remaining));\n }\n }).pipe(\n Effect.onExit(() =>\n Trace.annotate({\n \"browser.wait.timed-out\": timedOut,\n \"browser.wait.failed-polls\": failedPolls,\n ...(lastFailure === undefined ? {} : { \"browser.wait.last-failure\": lastFailure }),\n }),\n ),\n Trace.span(\"BrowserbaseRecordings.wait\", {\n attributes: { \"browser.operation\": \"recording-wait\" },\n }),\n );\n });\n\n const download = (ref: RecordingPageReference, limits: DownloadLimits) =>\n Stream.unwrap(\n Effect.gen(function* () {\n yield* Schema.decodeEffect(RecordingPageReference)(ref).pipe(\n Effect.mapError(() => failure(\"recording-download\", \"configuration\")),\n );\n\n const { maxBytes, timeoutMillis } = yield* transferPolicy(limits, () =>\n failure(\"recording-download\", \"configuration\"),\n );\n\n const deadline = yield* deadlineAfter(timeoutMillis);\n\n yield* within(authorize(ref.session), deadline, \"recording-download\");\n\n const latest = yield* within(\n read(ref.session, deadline),\n deadline,\n \"recording-download\",\n );\n\n const page = latest.downloads.find((entry) => entry.pageId === ref.pageId);\n\n if (page === undefined) return yield* failure(\"recording-download\", \"not-found\");\n if (page.status === \"FAILED\") return yield* failure(\"recording-download\", \"failed\");\n if (page.status !== \"COMPLETED\") return yield* failure(\"recording-download\", \"active\");\n if (page.downloadUrl === undefined) return yield* failure(\"recording-download\", \"byos\");\n\n // A fresh GET mints access for this subscription. No URL is persisted in the reference.\n return client\n .media(\n Redacted.make(page.downloadUrl),\n maxBytes,\n [\"video/mp4\", \"application/octet-stream\"],\n timeoutMillis,\n deadline,\n )\n .pipe(Stream.mapError(fromClient(\"recording-download\")));\n }),\n ).pipe(Trace.stream(\"BrowserbaseRecordings.download\"));\n\n return BrowserbaseRecordings.of({ request, status, wait, download });\n }),\n );\n}\n"],"mappings":"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"}
|
package/dist/Replays.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Identifier } from "./References.mjs";
|
|
2
2
|
import { ArtifactError } from "./Errors.mjs";
|
|
3
|
+
import { i as stream, r as span, t as BrowserbaseClient } from "./Client-BEC4Q8ZS.mjs";
|
|
3
4
|
import { RecordingPageReference, ReplayPage } from "./Transfers.mjs";
|
|
4
|
-
import { t as BrowserbaseClient } from "./Client-4RMKIpL2.mjs";
|
|
5
5
|
import { n as transferPolicy } from "./TransferPolicy-DQ06i7SZ.mjs";
|
|
6
|
-
import { t as BrowserbaseSessions } from "./Sessions-
|
|
6
|
+
import { t as BrowserbaseSessions } from "./Sessions-D2H5m6rF.mjs";
|
|
7
7
|
import { t as requireTerminalSession } from "./Authorization-Ll5f_XNM.mjs";
|
|
8
8
|
import { Clock, Context, Effect, Layer, Redacted, Schema, Stream } from "effect";
|
|
9
9
|
//#region src/Replays.ts
|
|
@@ -68,7 +68,7 @@ var BrowserbaseReplays = class BrowserbaseReplays extends Context.Service()("eff
|
|
|
68
68
|
startTimeMs: page.startTimeMs,
|
|
69
69
|
endTimeMs: page.endTimeMs
|
|
70
70
|
}));
|
|
71
|
-
});
|
|
71
|
+
}, span("BrowserbaseReplays.metadata"));
|
|
72
72
|
const openPage = Effect.fnUntraced(function* (ref) {
|
|
73
73
|
yield* Schema.decodeEffect(RecordingPageReference)(ref).pipe(Effect.mapError(() => failure("replay", "configuration")));
|
|
74
74
|
if (!(yield* metadata(ref.session)).some((page) => page.pageId === ref.pageId)) return yield* failure("replay", "not-found");
|
|
@@ -84,17 +84,17 @@ var BrowserbaseReplays = class BrowserbaseReplays extends Context.Service()("eff
|
|
|
84
84
|
mediaCount: urls.length,
|
|
85
85
|
media: (index, limits) => {
|
|
86
86
|
const url = Number.isSafeInteger(index) ? urls[index] : void 0;
|
|
87
|
-
return url === void 0 ? Stream.fail(failure("replay-media", "not-found")) : Stream.unwrap(transferPolicy({
|
|
87
|
+
return (url === void 0 ? Stream.fail(failure("replay-media", "not-found")) : Stream.unwrap(transferPolicy({
|
|
88
88
|
maxBytes: limits.maxBytes,
|
|
89
89
|
...limits.timeoutMillis === void 0 ? {} : { timeoutMillis: limits.timeoutMillis }
|
|
90
90
|
}, () => failure("replay-media", "configuration")).pipe(Effect.map(({ maxBytes, timeoutMillis }) => client.media(Redacted.make(url), maxBytes, [
|
|
91
91
|
"video/mp4",
|
|
92
92
|
"video/iso.segment",
|
|
93
93
|
"application/octet-stream"
|
|
94
|
-
], timeoutMillis).pipe(Stream.mapError(fromClient("replay-media"))))));
|
|
94
|
+
], timeoutMillis).pipe(Stream.mapError(fromClient("replay-media"))))))).pipe(stream("BrowserbaseReplays.media"));
|
|
95
95
|
}
|
|
96
96
|
};
|
|
97
|
-
});
|
|
97
|
+
}, span("BrowserbaseReplays.openPage"));
|
|
98
98
|
return BrowserbaseReplays.of({
|
|
99
99
|
metadata,
|
|
100
100
|
openPage
|
package/dist/Replays.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Replays.mjs","names":[],"sources":["../src/Replays.ts"],"sourcesContent":["import { Clock, Context, Effect, Layer, Redacted, Schema, Stream } from \"effect\";\n\nimport { BrowserbaseClient } from \"./Client.ts\";\nimport { ArtifactError, type ClientError } from \"./Errors.ts\";\nimport { requireTerminalSession } from \"./internal/artifact/Authorization.ts\";\nimport { transferPolicy } from \"./internal/artifact/TransferPolicy.ts\";\nimport { Identifier, type SessionReference } from \"./References.ts\";\nimport { BrowserbaseSessions } from \"./Sessions.ts\";\nimport {\n type ArtifactTransferPolicy as DownloadLimits,\n RecordingPageReference,\n ReplayPage,\n} from \"./Transfers.ts\";\n\nconst Metadata = Schema.Struct({\n pageCount: Schema.Natural,\n pages: Schema.Array(\n Schema.Struct({\n pageId: Identifier,\n startTimeMs: Schema.Finite,\n endTimeMs: Schema.Finite,\n url: Schema.String.check(Schema.isMaxLength(16384)),\n }),\n ).check(Schema.isMaxLength(256)),\n});\n\nconst failure = (operation: ArtifactError[\"operation\"], reason: ArtifactError[\"reason\"]) =>\n ArtifactError.make({ operation, reason });\n\nconst fromClient = (operation: ArtifactError[\"operation\"]) => (error: ClientError) =>\n ArtifactError.make({\n operation,\n reason: error.reason,\n ...(error.outcome === undefined ? {} : { outcome: error.outcome }),\n ...(error.status === undefined ? {} : { status: error.status }),\n ...(error.retryAfterMillis === undefined ? {} : { retryAfterMillis: error.retryAfterMillis }),\n });\n\nexport interface ReplayAccess {\n readonly reference: RecordingPageReference;\n /** Temporary playback material for an authorized host route; never includes the API key. */\n readonly playlist: Redacted.Redacted<string>;\n readonly fetchedAtMillis: number;\n readonly mediaCount: number;\n /** Optional host proxy of an indexed URI from this exact playlist; no arbitrary URL parameter. */\n readonly media: (\n index: number,\n limits: DownloadLimits,\n ) => Stream.Stream<Uint8Array, ArtifactError>;\n}\n\n/** Media-playlist validation, not a player. Unsupported URI-bearing tags fail closed. */\nconst playlistUrls = (body: string, allowed: (url: string) => boolean): ReadonlyArray<string> => {\n const lines = body.split(/\\r?\\n/);\n\n if (lines[0] !== \"#EXTM3U\" || !lines.includes(\"#EXT-X-ENDLIST\") || lines.length > 32768) {\n throw failure(\"replay-playlist\", \"malformed\");\n }\n const urls: string[] = [];\n\n for (const raw of lines.slice(1)) {\n const line = raw.trim();\n\n if (line === \"\") continue;\n if (\n line.startsWith(\"#EXT-X-STREAM-INF\") ||\n line.startsWith(\"#EXT-X-MEDIA:\") ||\n (line.startsWith(\"#EXT-X-KEY:\") && line !== \"#EXT-X-KEY:METHOD=NONE\")\n ) {\n throw failure(\"replay-playlist\", \"unsupported\");\n }\n let url: string | undefined;\n\n if (!line.startsWith(\"#\")) url = line;\n else if (/URI\\s*=/.test(line)) {\n if (!line.startsWith(\"#EXT-X-MAP:\")) throw failure(\"replay-playlist\", \"unsupported\");\n const match = /(?:^|,)URI=\"([^\"]+)\"(?:,|$)/.exec(line.slice(\"#EXT-X-MAP:\".length));\n\n if (match === null) throw failure(\"replay-playlist\", \"malformed\");\n url = match[1];\n }\n if (url !== undefined) {\n if (!allowed(url) || urls.length >= 16384) throw failure(\"replay-playlist\", \"unsafe-url\");\n urls.push(url);\n }\n }\n if (urls.length === 0) throw failure(\"replay-playlist\", \"malformed\");\n\n return urls;\n};\n\nexport class BrowserbaseReplays extends Context.Service<\n BrowserbaseReplays,\n {\n readonly metadata: (\n reference: SessionReference,\n ) => Effect.Effect<ReadonlyArray<ReplayPage>, ArtifactError>;\n readonly openPage: (\n reference: RecordingPageReference,\n ) => Effect.Effect<ReplayAccess, ArtifactError>;\n }\n>()(\"effect-browserbase/Replays\") {\n static readonly layer: Layer.Layer<\n BrowserbaseReplays,\n never,\n BrowserbaseClient | BrowserbaseSessions\n > = Layer.effect(\n BrowserbaseReplays,\n Effect.gen(function* () {\n const client = yield* BrowserbaseClient;\n const sessions = yield* BrowserbaseSessions;\n\n const metadata = Effect.fnUntraced(function* (ref: SessionReference) {\n yield* requireTerminalSession(\n sessions,\n ref,\n () => failure(\"replay\", \"active\"),\n (error) => ArtifactError.make({ operation: \"replay\", reason: error.reason }),\n );\n\n const raw = yield* client\n .json(\"GET\", `/v1/sessions/${encodeURIComponent(ref.sessionId)}/replays`)\n .pipe(\n Effect.mapError(fromClient(\"replay-metadata\")),\n Effect.flatMap((value) =>\n Schema.decodeUnknownEffect(Metadata)(value).pipe(\n Effect.mapError(() => failure(\"replay-metadata\", \"malformed\")),\n ),\n ),\n );\n\n if (\n raw.pageCount !== raw.pages.length ||\n new Set(raw.pages.map((page) => page.pageId)).size !== raw.pages.length ||\n raw.pages.some((page) => page.startTimeMs < 0 || page.endTimeMs < page.startTimeMs)\n ) {\n return yield* failure(\"replay-metadata\", \"malformed\");\n }\n\n return raw.pages.map((page) =>\n ReplayPage.make({\n pageId: page.pageId,\n startTimeMs: page.startTimeMs,\n endTimeMs: page.endTimeMs,\n }),\n );\n });\n\n const openPage = Effect.fnUntraced(function* (ref: RecordingPageReference) {\n yield* Schema.decodeEffect(RecordingPageReference)(ref).pipe(\n Effect.mapError(() => failure(\"replay\", \"configuration\")),\n );\n\n const pages = yield* metadata(ref.session);\n\n if (!pages.some((page) => page.pageId === ref.pageId))\n return yield* failure(\"replay\", \"not-found\");\n\n const body = yield* client\n .text(\n `/v1/sessions/${encodeURIComponent(ref.session.sessionId)}/replays/${encodeURIComponent(ref.pageId)}`,\n 1024 * 1024,\n [\"application/vnd.apple.mpegurl\", \"application/x-mpegurl\"],\n )\n .pipe(Effect.mapError(fromClient(\"replay-playlist\")));\n\n // One sanitized rejection: an unsupported tag and an unapproved URI are both\n // refusals to interpret the playlist, and neither may echo its contents.\n const urls = yield* Effect.try({\n try: () => playlistUrls(body, client.validateMediaUrl),\n catch: () => failure(\"replay-playlist\", \"malformed\"),\n });\n\n return {\n reference: ref,\n playlist: Redacted.make(body),\n fetchedAtMillis: yield* Clock.currentTimeMillis,\n mediaCount: urls.length,\n media: (index: number, limits: DownloadLimits) => {\n const url = Number.isSafeInteger(index) ? urls[index] : undefined;\n\n return url === undefined\n ? Stream.fail(failure(\"replay-media\", \"not-found\"))\n : Stream.unwrap(\n transferPolicy(\n {\n maxBytes: limits.maxBytes,\n ...(limits.timeoutMillis === undefined\n ? {}\n : { timeoutMillis: limits.timeoutMillis }),\n },\n () => failure(\"replay-media\", \"configuration\"),\n ).pipe(\n Effect.map(({ maxBytes, timeoutMillis }) =>\n client\n .media(\n Redacted.make(url),\n maxBytes,\n [\"video/mp4\", \"video/iso.segment\", \"application/octet-stream\"],\n timeoutMillis,\n )\n .pipe(Stream.mapError(fromClient(\"replay-media\"))),\n ),\n ),\n );\n },\n } satisfies ReplayAccess;\n });\n\n return BrowserbaseReplays.of({ metadata, openPage });\n }),\n );\n}\n"],"mappings":";;;;;;;;;AAcA,MAAM,WAAW,OAAO,OAAO;CAC7B,WAAW,OAAO;CAClB,OAAO,OAAO,MACZ,OAAO,OAAO;EACZ,QAAQ;EACR,aAAa,OAAO;EACpB,WAAW,OAAO;EAClB,KAAK,OAAO,OAAO,MAAM,OAAO,YAAY,KAAK,CAAC;CACpD,CAAC,CACH,CAAC,CAAC,MAAM,OAAO,YAAY,GAAG,CAAC;AACjC,CAAC;AAED,MAAM,WAAW,WAAuC,WACtD,cAAc,KAAK;CAAE;CAAW;AAAO,CAAC;AAE1C,MAAM,cAAc,eAA2C,UAC7D,cAAc,KAAK;CACjB;CACA,QAAQ,MAAM;CACd,GAAI,MAAM,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,MAAM,QAAQ;CAChE,GAAI,MAAM,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,MAAM,OAAO;CAC7D,GAAI,MAAM,qBAAqB,KAAA,IAAY,CAAC,IAAI,EAAE,kBAAkB,MAAM,iBAAiB;AAC7F,CAAC;;AAgBH,MAAM,gBAAgB,MAAc,YAA6D;CAC/F,MAAM,QAAQ,KAAK,MAAM,OAAO;CAEhC,IAAI,MAAM,OAAO,aAAa,CAAC,MAAM,SAAS,gBAAgB,KAAK,MAAM,SAAS,OAChF,MAAM,QAAQ,mBAAmB,WAAW;CAE9C,MAAM,OAAiB,CAAC;CAExB,KAAK,MAAM,OAAO,MAAM,MAAM,CAAC,GAAG;EAChC,MAAM,OAAO,IAAI,KAAK;EAEtB,IAAI,SAAS,IAAI;EACjB,IACE,KAAK,WAAW,mBAAmB,KACnC,KAAK,WAAW,eAAe,KAC9B,KAAK,WAAW,aAAa,KAAK,SAAS,0BAE5C,MAAM,QAAQ,mBAAmB,aAAa;EAEhD,IAAI;EAEJ,IAAI,CAAC,KAAK,WAAW,GAAG,GAAG,MAAM;OAC5B,IAAI,UAAU,KAAK,IAAI,GAAG;GAC7B,IAAI,CAAC,KAAK,WAAW,aAAa,GAAG,MAAM,QAAQ,mBAAmB,aAAa;GACnF,MAAM,QAAQ,8BAA8B,KAAK,KAAK,MAAM,EAAoB,CAAC;GAEjF,IAAI,UAAU,MAAM,MAAM,QAAQ,mBAAmB,WAAW;GAChE,MAAM,MAAM;EACd;EACA,IAAI,QAAQ,KAAA,GAAW;GACrB,IAAI,CAAC,QAAQ,GAAG,KAAK,KAAK,UAAU,OAAO,MAAM,QAAQ,mBAAmB,YAAY;GACxF,KAAK,KAAK,GAAG;EACf;CACF;CACA,IAAI,KAAK,WAAW,GAAG,MAAM,QAAQ,mBAAmB,WAAW;CAEnE,OAAO;AACT;AAEA,IAAa,qBAAb,MAAa,2BAA2B,QAAQ,QAU9C,CAAC,CAAC,4BAA4B,CAAC,CAAC;CAChC,OAAgB,QAIZ,MAAM,OACR,oBACA,OAAO,IAAI,aAAa;EACtB,MAAM,SAAS,OAAO;EACtB,MAAM,WAAW,OAAO;EAExB,MAAM,WAAW,OAAO,WAAW,WAAW,KAAuB;GACnE,OAAO,uBACL,UACA,WACM,QAAQ,UAAU,QAAQ,IAC/B,UAAU,cAAc,KAAK;IAAE,WAAW;IAAU,QAAQ,MAAM;GAAO,CAAC,CAC7E;GAEA,MAAM,MAAM,OAAO,OAChB,KAAK,OAAO,gBAAgB,mBAAmB,IAAI,SAAS,EAAE,SAAS,CAAC,CACxE,KACC,OAAO,SAAS,WAAW,iBAAiB,CAAC,GAC7C,OAAO,SAAS,UACd,OAAO,oBAAoB,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,KAC1C,OAAO,eAAe,QAAQ,mBAAmB,WAAW,CAAC,CAC/D,CACF,CACF;GAEF,IACE,IAAI,cAAc,IAAI,MAAM,UAC5B,IAAI,IAAI,IAAI,MAAM,KAAK,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,SAAS,IAAI,MAAM,UACjE,IAAI,MAAM,MAAM,SAAS,KAAK,cAAc,KAAK,KAAK,YAAY,KAAK,WAAW,GAElF,OAAO,OAAO,QAAQ,mBAAmB,WAAW;GAGtD,OAAO,IAAI,MAAM,KAAK,SACpB,WAAW,KAAK;IACd,QAAQ,KAAK;IACb,aAAa,KAAK;IAClB,WAAW,KAAK;GAClB,CAAC,CACH;EACF,CAAC;EAED,MAAM,WAAW,OAAO,WAAW,WAAW,KAA6B;GACzE,OAAO,OAAO,aAAa,sBAAsB,CAAC,CAAC,GAAG,CAAC,CAAC,KACtD,OAAO,eAAe,QAAQ,UAAU,eAAe,CAAC,CAC1D;GAIA,IAAI,EAAC,OAFgB,SAAS,IAAI,OAAO,EAAA,CAE9B,MAAM,SAAS,KAAK,WAAW,IAAI,MAAM,GAClD,OAAO,OAAO,QAAQ,UAAU,WAAW;GAE7C,MAAM,OAAO,OAAO,OACjB,KACC,gBAAgB,mBAAmB,IAAI,QAAQ,SAAS,EAAE,WAAW,mBAAmB,IAAI,MAAM,KAClG,SACA,CAAC,iCAAiC,uBAAuB,CAC3D,CAAC,CACA,KAAK,OAAO,SAAS,WAAW,iBAAiB,CAAC,CAAC;GAItD,MAAM,OAAO,OAAO,OAAO,IAAI;IAC7B,WAAW,aAAa,MAAM,OAAO,gBAAgB;IACrD,aAAa,QAAQ,mBAAmB,WAAW;GACrD,CAAC;GAED,OAAO;IACL,WAAW;IACX,UAAU,SAAS,KAAK,IAAI;IAC5B,iBAAiB,OAAO,MAAM;IAC9B,YAAY,KAAK;IACjB,QAAQ,OAAe,WAA2B;KAChD,MAAM,MAAM,OAAO,cAAc,KAAK,IAAI,KAAK,SAAS,KAAA;KAExD,OAAO,QAAQ,KAAA,IACX,OAAO,KAAK,QAAQ,gBAAgB,WAAW,CAAC,IAChD,OAAO,OACL,eACE;MACE,UAAU,OAAO;MACjB,GAAI,OAAO,kBAAkB,KAAA,IACzB,CAAC,IACD,EAAE,eAAe,OAAO,cAAc;KAC5C,SACM,QAAQ,gBAAgB,eAAe,CAC/C,CAAC,CAAC,KACA,OAAO,KAAK,EAAE,UAAU,oBACtB,OACG,MACC,SAAS,KAAK,GAAG,GACjB,UACA;MAAC;MAAa;MAAqB;KAA0B,GAC7D,aACF,CAAC,CACA,KAAK,OAAO,SAAS,WAAW,cAAc,CAAC,CAAC,CACrD,CACF,CACF;IACN;GACF;EACF,CAAC;EAED,OAAO,mBAAmB,GAAG;GAAE;GAAU;EAAS,CAAC;CACrD,CAAC,CACH;AACF"}
|
|
1
|
+
{"version":3,"file":"Replays.mjs","names":["Trace.span","Trace.stream"],"sources":["../src/Replays.ts"],"sourcesContent":["import { Clock, Context, Effect, Layer, Redacted, Schema, Stream } from \"effect\";\n\nimport { BrowserbaseClient } from \"./Client.ts\";\nimport { ArtifactError, type ClientError } from \"./Errors.ts\";\nimport { requireTerminalSession } from \"./internal/artifact/Authorization.ts\";\nimport { transferPolicy } from \"./internal/artifact/TransferPolicy.ts\";\nimport * as Trace from \"./internal/Trace.ts\";\nimport { Identifier, type SessionReference } from \"./References.ts\";\nimport { BrowserbaseSessions } from \"./Sessions.ts\";\nimport {\n type ArtifactTransferPolicy as DownloadLimits,\n RecordingPageReference,\n ReplayPage,\n} from \"./Transfers.ts\";\n\nconst Metadata = Schema.Struct({\n pageCount: Schema.Natural,\n pages: Schema.Array(\n Schema.Struct({\n pageId: Identifier,\n startTimeMs: Schema.Finite,\n endTimeMs: Schema.Finite,\n url: Schema.String.check(Schema.isMaxLength(16384)),\n }),\n ).check(Schema.isMaxLength(256)),\n});\n\nconst failure = (operation: ArtifactError[\"operation\"], reason: ArtifactError[\"reason\"]) =>\n ArtifactError.make({ operation, reason });\n\nconst fromClient = (operation: ArtifactError[\"operation\"]) => (error: ClientError) =>\n ArtifactError.make({\n operation,\n reason: error.reason,\n ...(error.outcome === undefined ? {} : { outcome: error.outcome }),\n ...(error.status === undefined ? {} : { status: error.status }),\n ...(error.retryAfterMillis === undefined ? {} : { retryAfterMillis: error.retryAfterMillis }),\n });\n\nexport interface ReplayAccess {\n readonly reference: RecordingPageReference;\n /** Temporary playback material for an authorized host route; never includes the API key. */\n readonly playlist: Redacted.Redacted<string>;\n readonly fetchedAtMillis: number;\n readonly mediaCount: number;\n /** Optional host proxy of an indexed URI from this exact playlist; no arbitrary URL parameter. */\n readonly media: (\n index: number,\n limits: DownloadLimits,\n ) => Stream.Stream<Uint8Array, ArtifactError>;\n}\n\n/** Media-playlist validation, not a player. Unsupported URI-bearing tags fail closed. */\nconst playlistUrls = (body: string, allowed: (url: string) => boolean): ReadonlyArray<string> => {\n const lines = body.split(/\\r?\\n/);\n\n if (lines[0] !== \"#EXTM3U\" || !lines.includes(\"#EXT-X-ENDLIST\") || lines.length > 32768) {\n throw failure(\"replay-playlist\", \"malformed\");\n }\n const urls: string[] = [];\n\n for (const raw of lines.slice(1)) {\n const line = raw.trim();\n\n if (line === \"\") continue;\n if (\n line.startsWith(\"#EXT-X-STREAM-INF\") ||\n line.startsWith(\"#EXT-X-MEDIA:\") ||\n (line.startsWith(\"#EXT-X-KEY:\") && line !== \"#EXT-X-KEY:METHOD=NONE\")\n ) {\n throw failure(\"replay-playlist\", \"unsupported\");\n }\n let url: string | undefined;\n\n if (!line.startsWith(\"#\")) url = line;\n else if (/URI\\s*=/.test(line)) {\n if (!line.startsWith(\"#EXT-X-MAP:\")) throw failure(\"replay-playlist\", \"unsupported\");\n const match = /(?:^|,)URI=\"([^\"]+)\"(?:,|$)/.exec(line.slice(\"#EXT-X-MAP:\".length));\n\n if (match === null) throw failure(\"replay-playlist\", \"malformed\");\n url = match[1];\n }\n if (url !== undefined) {\n if (!allowed(url) || urls.length >= 16384) throw failure(\"replay-playlist\", \"unsafe-url\");\n urls.push(url);\n }\n }\n if (urls.length === 0) throw failure(\"replay-playlist\", \"malformed\");\n\n return urls;\n};\n\nexport class BrowserbaseReplays extends Context.Service<\n BrowserbaseReplays,\n {\n readonly metadata: (\n reference: SessionReference,\n ) => Effect.Effect<ReadonlyArray<ReplayPage>, ArtifactError>;\n readonly openPage: (\n reference: RecordingPageReference,\n ) => Effect.Effect<ReplayAccess, ArtifactError>;\n }\n>()(\"effect-browserbase/Replays\") {\n static readonly layer: Layer.Layer<\n BrowserbaseReplays,\n never,\n BrowserbaseClient | BrowserbaseSessions\n > = Layer.effect(\n BrowserbaseReplays,\n Effect.gen(function* () {\n const client = yield* BrowserbaseClient;\n const sessions = yield* BrowserbaseSessions;\n\n const metadata = Effect.fnUntraced(function* (ref: SessionReference) {\n yield* requireTerminalSession(\n sessions,\n ref,\n () => failure(\"replay\", \"active\"),\n (error) => ArtifactError.make({ operation: \"replay\", reason: error.reason }),\n );\n\n const raw = yield* client\n .json(\"GET\", `/v1/sessions/${encodeURIComponent(ref.sessionId)}/replays`)\n .pipe(\n Effect.mapError(fromClient(\"replay-metadata\")),\n Effect.flatMap((value) =>\n Schema.decodeUnknownEffect(Metadata)(value).pipe(\n Effect.mapError(() => failure(\"replay-metadata\", \"malformed\")),\n ),\n ),\n );\n\n if (\n raw.pageCount !== raw.pages.length ||\n new Set(raw.pages.map((page) => page.pageId)).size !== raw.pages.length ||\n raw.pages.some((page) => page.startTimeMs < 0 || page.endTimeMs < page.startTimeMs)\n ) {\n return yield* failure(\"replay-metadata\", \"malformed\");\n }\n\n return raw.pages.map((page) =>\n ReplayPage.make({\n pageId: page.pageId,\n startTimeMs: page.startTimeMs,\n endTimeMs: page.endTimeMs,\n }),\n );\n }, Trace.span(\"BrowserbaseReplays.metadata\"));\n\n const openPage = Effect.fnUntraced(function* (ref: RecordingPageReference) {\n yield* Schema.decodeEffect(RecordingPageReference)(ref).pipe(\n Effect.mapError(() => failure(\"replay\", \"configuration\")),\n );\n\n const pages = yield* metadata(ref.session);\n\n if (!pages.some((page) => page.pageId === ref.pageId))\n return yield* failure(\"replay\", \"not-found\");\n\n const body = yield* client\n .text(\n `/v1/sessions/${encodeURIComponent(ref.session.sessionId)}/replays/${encodeURIComponent(ref.pageId)}`,\n 1024 * 1024,\n [\"application/vnd.apple.mpegurl\", \"application/x-mpegurl\"],\n )\n .pipe(Effect.mapError(fromClient(\"replay-playlist\")));\n\n // One sanitized rejection: an unsupported tag and an unapproved URI are both\n // refusals to interpret the playlist, and neither may echo its contents.\n const urls = yield* Effect.try({\n try: () => playlistUrls(body, client.validateMediaUrl),\n catch: () => failure(\"replay-playlist\", \"malformed\"),\n });\n\n return {\n reference: ref,\n playlist: Redacted.make(body),\n fetchedAtMillis: yield* Clock.currentTimeMillis,\n mediaCount: urls.length,\n media: (index: number, limits: DownloadLimits) => {\n const url = Number.isSafeInteger(index) ? urls[index] : undefined;\n\n return (\n url === undefined\n ? Stream.fail(failure(\"replay-media\", \"not-found\"))\n : Stream.unwrap(\n transferPolicy(\n {\n maxBytes: limits.maxBytes,\n ...(limits.timeoutMillis === undefined\n ? {}\n : { timeoutMillis: limits.timeoutMillis }),\n },\n () => failure(\"replay-media\", \"configuration\"),\n ).pipe(\n Effect.map(({ maxBytes, timeoutMillis }) =>\n client\n .media(\n Redacted.make(url),\n maxBytes,\n [\"video/mp4\", \"video/iso.segment\", \"application/octet-stream\"],\n timeoutMillis,\n )\n .pipe(Stream.mapError(fromClient(\"replay-media\"))),\n ),\n ),\n )\n ).pipe(Trace.stream(\"BrowserbaseReplays.media\"));\n },\n } satisfies ReplayAccess;\n }, Trace.span(\"BrowserbaseReplays.openPage\"));\n\n return BrowserbaseReplays.of({ metadata, openPage });\n }),\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { r as span } from "./Client-BEC4Q8ZS.mjs";
|
|
1
2
|
import { Effect, Schema } from "effect";
|
|
2
3
|
//#region src/internal/http/Resource.ts
|
|
3
4
|
/**
|
|
@@ -24,8 +25,11 @@ const resource = (client, make) => {
|
|
|
24
25
|
});
|
|
25
26
|
/** Rejects unknown or invalid caller input before any request is built. */
|
|
26
27
|
const input = (schema, value, operation) => Schema.decodeUnknownEffect(schema)(value, { onExcessProperty: "error" }).pipe(Effect.mapError(() => configuration(operation)));
|
|
27
|
-
const request = (method, path, reply, operation, body) => client.json(method, path, body).pipe(Effect.mapError(fromClient(operation)), Effect.flatMap((raw) => Schema.decodeEffect(reply)(raw).pipe(Effect.mapError(() => malformed(operation, method !== "GET")))));
|
|
28
|
-
const remove = (path, operation) => client.noContent("DELETE", path).pipe(Effect.mapError(fromClient(operation))
|
|
28
|
+
const request = (method, path, reply, operation, body) => client.json(method, path, body).pipe(Effect.mapError(fromClient(operation)), Effect.flatMap((raw) => Schema.decodeEffect(reply)(raw).pipe(Effect.mapError(() => malformed(operation, method !== "GET")))), span("Browserbase.resource.request", { attributes: { "browser.operation": operation } }));
|
|
29
|
+
const remove = (path, operation) => client.noContent("DELETE", path).pipe(Effect.mapError(fromClient(operation)), span("Browserbase.resource.remove", { attributes: {
|
|
30
|
+
"browser.operation": operation,
|
|
31
|
+
"http.request.method": "DELETE"
|
|
32
|
+
} }));
|
|
29
33
|
const segment = (id) => encodeURIComponent(id);
|
|
30
34
|
const query = (entries) => {
|
|
31
35
|
const search = new URLSearchParams();
|
|
@@ -47,4 +51,4 @@ const resource = (client, make) => {
|
|
|
47
51
|
//#endregion
|
|
48
52
|
export { resource as t };
|
|
49
53
|
|
|
50
|
-
//# sourceMappingURL=Resource-
|
|
54
|
+
//# sourceMappingURL=Resource-J7Kkk5mu.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Resource-J7Kkk5mu.mjs","names":["Trace.span"],"sources":["../src/internal/http/Resource.ts"],"sourcesContent":["import { Effect, Schema } from \"effect\";\n\nimport type { BrowserbaseClient, ClientMethod } from \"../../Client.ts\";\nimport type { ClientError } from \"../../Errors.ts\";\nimport * as Trace from \"../Trace.ts\";\n\ntype Reason = ClientError[\"reason\"];\ntype Outcome = NonNullable<ClientError[\"outcome\"]>;\n\nexport interface RequestFailure<Operation extends string> {\n readonly operation: Operation;\n readonly reason: Reason;\n readonly outcome?: Outcome;\n readonly status?: number;\n readonly retryAfterMillis?: number;\n}\n\n/**\n * The shared shape of every control-plane resource: strict input decoding, tolerant reply\n * decoding, and one mapping from transport failures into the resource's own error.\n */\nexport const resource = <E extends { readonly operation: string }>(\n client: BrowserbaseClient[\"Service\"],\n make: (failure: RequestFailure<E[\"operation\"]>) => E,\n) => {\n type Operation = E[\"operation\"];\n\n const fromClient = (operation: Operation) => (error: ClientError) =>\n make({\n operation,\n reason: error.reason,\n ...(error.outcome === undefined ? {} : { outcome: error.outcome }),\n ...(error.status === undefined ? {} : { status: error.status }),\n ...(error.retryAfterMillis === undefined ? {} : { retryAfterMillis: error.retryAfterMillis }),\n });\n\n const configuration = (operation: Operation) =>\n make({ operation, reason: \"configuration\", outcome: \"undispatched\" });\n\n const malformed = (operation: Operation, mutation: boolean) =>\n make({ operation, reason: \"malformed\", ...(mutation ? { outcome: \"unknown\" } : {}) });\n\n /** Rejects unknown or invalid caller input before any request is built. */\n const input = <A>(\n schema: Schema.Codec<A, unknown, never, never>,\n value: unknown,\n operation: Operation,\n ): Effect.Effect<A, E> =>\n Schema.decodeUnknownEffect(schema)(value, { onExcessProperty: \"error\" }).pipe(\n Effect.mapError(() => configuration(operation)),\n );\n\n const request = <A>(\n method: ClientMethod,\n path: string,\n reply: Schema.Codec<A, unknown, never, never>,\n operation: Operation,\n body?: Schema.Json,\n ): Effect.Effect<A, E> =>\n client.json(method, path, body).pipe(\n Effect.mapError(fromClient(operation)),\n Effect.flatMap((raw) =>\n Schema.decodeEffect(reply)(raw).pipe(\n Effect.mapError(() => malformed(operation, method !== \"GET\")),\n ),\n ),\n Trace.span(\"Browserbase.resource.request\", {\n attributes: { \"browser.operation\": operation },\n }),\n );\n\n const remove = (path: string, operation: Operation): Effect.Effect<void, E> =>\n client.noContent(\"DELETE\", path).pipe(\n Effect.mapError(fromClient(operation)),\n Trace.span(\"Browserbase.resource.remove\", {\n attributes: { \"browser.operation\": operation, \"http.request.method\": \"DELETE\" },\n }),\n );\n\n const segment = (id: string) => encodeURIComponent(id);\n\n const query = (entries: Record<string, string | number | boolean | undefined>) => {\n const search = new URLSearchParams();\n\n for (const [key, value] of Object.entries(entries))\n if (value !== undefined) search.set(key, String(value));\n\n return search.size === 0 ? \"\" : `?${search}`;\n };\n\n return { fromClient, configuration, malformed, input, request, remove, segment, query, make };\n};\n"],"mappings":";;;;;;;AAqBA,MAAa,YACX,QACA,SACG;CAGH,MAAM,cAAc,eAA0B,UAC5C,KAAK;EACH;EACA,QAAQ,MAAM;EACd,GAAI,MAAM,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,MAAM,QAAQ;EAChE,GAAI,MAAM,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,MAAM,OAAO;EAC7D,GAAI,MAAM,qBAAqB,KAAA,IAAY,CAAC,IAAI,EAAE,kBAAkB,MAAM,iBAAiB;CAC7F,CAAC;CAEH,MAAM,iBAAiB,cACrB,KAAK;EAAE;EAAW,QAAQ;EAAiB,SAAS;CAAe,CAAC;CAEtE,MAAM,aAAa,WAAsB,aACvC,KAAK;EAAE;EAAW,QAAQ;EAAa,GAAI,WAAW,EAAE,SAAS,UAAU,IAAI,CAAC;CAAG,CAAC;;CAGtF,MAAM,SACJ,QACA,OACA,cAEA,OAAO,oBAAoB,MAAM,CAAC,CAAC,OAAO,EAAE,kBAAkB,QAAQ,CAAC,CAAC,CAAC,KACvE,OAAO,eAAe,cAAc,SAAS,CAAC,CAChD;CAEF,MAAM,WACJ,QACA,MACA,OACA,WACA,SAEA,OAAO,KAAK,QAAQ,MAAM,IAAI,CAAC,CAAC,KAC9B,OAAO,SAAS,WAAW,SAAS,CAAC,GACrC,OAAO,SAAS,QACd,OAAO,aAAa,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,KAC9B,OAAO,eAAe,UAAU,WAAW,WAAW,KAAK,CAAC,CAC9D,CACF,GACAA,KAAW,gCAAgC,EACzC,YAAY,EAAE,qBAAqB,UAAU,EAC/C,CAAC,CACH;CAEF,MAAM,UAAU,MAAc,cAC5B,OAAO,UAAU,UAAU,IAAI,CAAC,CAAC,KAC/B,OAAO,SAAS,WAAW,SAAS,CAAC,GACrCA,KAAW,+BAA+B,EACxC,YAAY;EAAE,qBAAqB;EAAW,uBAAuB;CAAS,EAChF,CAAC,CACH;CAEF,MAAM,WAAW,OAAe,mBAAmB,EAAE;CAErD,MAAM,SAAS,YAAmE;EAChF,MAAM,SAAS,IAAI,gBAAgB;EAEnC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,GAC/C,IAAI,UAAU,KAAA,GAAW,OAAO,IAAI,KAAK,OAAO,KAAK,CAAC;EAExD,OAAO,OAAO,SAAS,IAAI,KAAK,IAAI;CACtC;CAEA,OAAO;EAAE;EAAY;EAAe;EAAW;EAAO;EAAS;EAAQ;EAAS;EAAO;CAAK;AAC9F"}
|
package/dist/Search.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PlatformError } from "./Errors.mjs";
|
|
2
|
-
import { t as BrowserbaseClient } from "./Client-
|
|
3
|
-
import { t as resource } from "./Resource-
|
|
2
|
+
import { r as span, t as BrowserbaseClient } from "./Client-BEC4Q8ZS.mjs";
|
|
3
|
+
import { t as resource } from "./Resource-J7Kkk5mu.mjs";
|
|
4
4
|
import { Context, Effect, Layer, Schema } from "effect";
|
|
5
5
|
//#region src/Search.ts
|
|
6
6
|
const Text = Schema.String.check(Schema.isMaxLength(16384));
|
|
@@ -33,10 +33,10 @@ var BrowserbaseSearch = class BrowserbaseSearch extends Context.Service()("effec
|
|
|
33
33
|
...failure,
|
|
34
34
|
service: "search"
|
|
35
35
|
}));
|
|
36
|
-
const web = Effect.
|
|
36
|
+
const web = Effect.fnUntraced(function* (query) {
|
|
37
37
|
const value = yield* api.input(SearchQuery, query, "search-web");
|
|
38
38
|
return yield* api.request("POST", "/v1/search", SearchResults, "search-web", value);
|
|
39
|
-
});
|
|
39
|
+
}, span("BrowserbaseSearch.web"));
|
|
40
40
|
return BrowserbaseSearch.of({ web });
|
|
41
41
|
}));
|
|
42
42
|
};
|
package/dist/Search.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Search.mjs","names":[],"sources":["../src/Search.ts"],"sourcesContent":["import { Context, Effect, Layer, Schema } from \"effect\";\n\nimport { BrowserbaseClient } from \"./Client.ts\";\nimport { PlatformError } from \"./Errors.ts\";\nimport { resource } from \"./internal/http/Resource.ts\";\n\nconst Text = Schema.String.check(Schema.isMaxLength(16_384));\n\nexport const SearchQuery = Schema.Struct({\n query: Schema.NonEmptyString.check(Schema.isMaxLength(2048)),\n /** 1–25; the provider defaults to 10. */\n numResults: Schema.optionalKey(Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 25 }))),\n});\n\nexport type SearchQuery = typeof SearchQuery.Type;\n\nexport class SearchResult extends Schema.Class<SearchResult>(\"BrowserbaseSearchResult\")({\n id: Text,\n url: Text,\n title: Text,\n author: Schema.optionalKey(Text),\n publishedDate: Schema.optionalKey(Text),\n image: Schema.optionalKey(Text),\n favicon: Schema.optionalKey(Text),\n}) {}\n\nexport class SearchResults extends Schema.Class<SearchResults>(\"BrowserbaseSearchResults\")({\n requestId: Text,\n query: Text,\n results: Schema.Array(SearchResult).check(Schema.isMaxLength(25)),\n}) {}\n\n/** Browserbase web search. The POST is never retried; billing of each outcome is provider-owned. */\nexport class BrowserbaseSearch extends Context.Service<\n BrowserbaseSearch,\n {\n readonly web: (query: SearchQuery) => Effect.Effect<SearchResults, PlatformError>;\n }\n>()(\"effect-browserbase/Search\") {\n static readonly layer: Layer.Layer<BrowserbaseSearch, never, BrowserbaseClient> = Layer.effect(\n BrowserbaseSearch,\n Effect.gen(function* () {\n const api = resource<PlatformError>(yield* BrowserbaseClient, (failure) =>\n PlatformError.make({ ...failure, service: \"search\" }),\n );\n\n const web = Effect.
|
|
1
|
+
{"version":3,"file":"Search.mjs","names":["Trace.span"],"sources":["../src/Search.ts"],"sourcesContent":["import { Context, Effect, Layer, Schema } from \"effect\";\n\nimport { BrowserbaseClient } from \"./Client.ts\";\nimport { PlatformError } from \"./Errors.ts\";\nimport { resource } from \"./internal/http/Resource.ts\";\nimport * as Trace from \"./internal/Trace.ts\";\n\nconst Text = Schema.String.check(Schema.isMaxLength(16_384));\n\nexport const SearchQuery = Schema.Struct({\n query: Schema.NonEmptyString.check(Schema.isMaxLength(2048)),\n /** 1–25; the provider defaults to 10. */\n numResults: Schema.optionalKey(Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 25 }))),\n});\n\nexport type SearchQuery = typeof SearchQuery.Type;\n\nexport class SearchResult extends Schema.Class<SearchResult>(\"BrowserbaseSearchResult\")({\n id: Text,\n url: Text,\n title: Text,\n author: Schema.optionalKey(Text),\n publishedDate: Schema.optionalKey(Text),\n image: Schema.optionalKey(Text),\n favicon: Schema.optionalKey(Text),\n}) {}\n\nexport class SearchResults extends Schema.Class<SearchResults>(\"BrowserbaseSearchResults\")({\n requestId: Text,\n query: Text,\n results: Schema.Array(SearchResult).check(Schema.isMaxLength(25)),\n}) {}\n\n/** Browserbase web search. The POST is never retried; billing of each outcome is provider-owned. */\nexport class BrowserbaseSearch extends Context.Service<\n BrowserbaseSearch,\n {\n readonly web: (query: SearchQuery) => Effect.Effect<SearchResults, PlatformError>;\n }\n>()(\"effect-browserbase/Search\") {\n static readonly layer: Layer.Layer<BrowserbaseSearch, never, BrowserbaseClient> = Layer.effect(\n BrowserbaseSearch,\n Effect.gen(function* () {\n const api = resource<PlatformError>(yield* BrowserbaseClient, (failure) =>\n PlatformError.make({ ...failure, service: \"search\" }),\n );\n\n const web = Effect.fnUntraced(function* (query: SearchQuery) {\n const value = yield* api.input(SearchQuery, query, \"search-web\");\n\n return yield* api.request(\"POST\", \"/v1/search\", SearchResults, \"search-web\", value);\n }, Trace.span(\"BrowserbaseSearch.web\"));\n\n return BrowserbaseSearch.of({ web });\n }),\n );\n}\n"],"mappings":";;;;;AAOA,MAAM,OAAO,OAAO,OAAO,MAAM,OAAO,YAAY,KAAM,CAAC;AAE3D,MAAa,cAAc,OAAO,OAAO;CACvC,OAAO,OAAO,eAAe,MAAM,OAAO,YAAY,IAAI,CAAC;;CAE3D,YAAY,OAAO,YAAY,OAAO,IAAI,MAAM,OAAO,UAAU;EAAE,SAAS;EAAG,SAAS;CAAG,CAAC,CAAC,CAAC;AAChG,CAAC;AAID,IAAa,eAAb,cAAkC,OAAO,MAAoB,yBAAyB,CAAC,CAAC;CACtF,IAAI;CACJ,KAAK;CACL,OAAO;CACP,QAAQ,OAAO,YAAY,IAAI;CAC/B,eAAe,OAAO,YAAY,IAAI;CACtC,OAAO,OAAO,YAAY,IAAI;CAC9B,SAAS,OAAO,YAAY,IAAI;AAClC,CAAC,CAAC,CAAC,CAAC;AAEJ,IAAa,gBAAb,cAAmC,OAAO,MAAqB,0BAA0B,CAAC,CAAC;CACzF,WAAW;CACX,OAAO;CACP,SAAS,OAAO,MAAM,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,EAAE,CAAC;AAClE,CAAC,CAAC,CAAC,CAAC;;AAGJ,IAAa,oBAAb,MAAa,0BAA0B,QAAQ,QAK7C,CAAC,CAAC,2BAA2B,CAAC,CAAC;CAC/B,OAAgB,QAAkE,MAAM,OACtF,mBACA,OAAO,IAAI,aAAa;EACtB,MAAM,MAAM,SAAwB,OAAO,oBAAoB,YAC7D,cAAc,KAAK;GAAE,GAAG;GAAS,SAAS;EAAS,CAAC,CACtD;EAEA,MAAM,MAAM,OAAO,WAAW,WAAW,OAAoB;GAC3D,MAAM,QAAQ,OAAO,IAAI,MAAM,aAAa,OAAO,YAAY;GAE/D,OAAO,OAAO,IAAI,QAAQ,QAAQ,cAAc,eAAe,cAAc,KAAK;EACpF,GAAGA,KAAW,uBAAuB,CAAC;EAEtC,OAAO,kBAAkB,GAAG,EAAE,IAAI,CAAC;CACrC,CAAC,CACH;AACF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Identifier, SessionReference } from "./References.mjs";
|
|
2
2
|
import { ClientError, SessionError } from "./Errors.mjs";
|
|
3
|
-
import { t as BrowserbaseClient } from "./Client-
|
|
3
|
+
import { r as span, t as BrowserbaseClient } from "./Client-BEC4Q8ZS.mjs";
|
|
4
4
|
import { ProviderSession, SessionMetadata, SessionStatus, isTerminalSessionStatus } from "./SessionData.mjs";
|
|
5
5
|
import { Clock, Context, Effect, Layer, Redacted, Schema } from "effect";
|
|
6
6
|
import { BrowserError, Reasons } from "effect-browser/errors";
|
|
@@ -175,10 +175,10 @@ var BrowserbaseSessions = class BrowserbaseSessions extends Context.Service()("e
|
|
|
175
175
|
const raw = yield* client.json("GET", `/v1/sessions/${encodeURIComponent(ref.sessionId)}`, void 0, deadline).pipe(Effect.mapError((error) => fromClient("session-retrieve", error)));
|
|
176
176
|
return yield* decode(raw, "session-retrieve", ref);
|
|
177
177
|
});
|
|
178
|
-
const retrieve = Effect.
|
|
178
|
+
const retrieve = Effect.fnUntraced(function* (reference) {
|
|
179
179
|
return yield* read(reference);
|
|
180
|
-
});
|
|
181
|
-
const list = Effect.
|
|
180
|
+
}, span("BrowserbaseSessions.retrieve"));
|
|
181
|
+
const list = Effect.fnUntraced(function* (query = {}) {
|
|
182
182
|
const checked = yield* Schema.decodeEffect(SessionListQuery)(query, { onExcessProperty: "error" }).pipe(Effect.mapError(() => configuration("session-list")));
|
|
183
183
|
const search = new URLSearchParams();
|
|
184
184
|
if (checked.status !== void 0) search.set("status", checked.status);
|
|
@@ -189,15 +189,15 @@ var BrowserbaseSessions = class BrowserbaseSessions extends Context.Service()("e
|
|
|
189
189
|
const output = [];
|
|
190
190
|
for (const row of rows) output.push(yield* decode(row, "session-list"));
|
|
191
191
|
return output;
|
|
192
|
-
});
|
|
193
|
-
const requestRelease = Effect.
|
|
192
|
+
}, span("BrowserbaseSessions.list"));
|
|
193
|
+
const requestRelease = Effect.fnUntraced(function* (reference) {
|
|
194
194
|
const ref = yield* validate(reference, "session-release");
|
|
195
195
|
const raw = yield* client.json("POST", `/v1/sessions/${encodeURIComponent(ref.sessionId)}`, {
|
|
196
196
|
projectId: ref.projectId,
|
|
197
197
|
status: "REQUEST_RELEASE"
|
|
198
198
|
}).pipe(Effect.mapError((error) => fromClient("session-release", error)));
|
|
199
199
|
return yield* decode(raw, "session-release", ref, true);
|
|
200
|
-
});
|
|
200
|
+
}, span("BrowserbaseSessions.requestRelease"));
|
|
201
201
|
const wait = Effect.fnUntraced(function* (reference, options, untilRunning) {
|
|
202
202
|
const bounds = yield* Schema.decodeEffect(SessionWaitOptions)(options, { onExcessProperty: "error" }).pipe(Effect.mapError(() => configuration("session-wait")));
|
|
203
203
|
const deadline = (yield* now) + bounds.timeoutMillis;
|
|
@@ -207,7 +207,7 @@ var BrowserbaseSessions = class BrowserbaseSessions extends Context.Service()("e
|
|
|
207
207
|
operation: "session-wait",
|
|
208
208
|
reason: "timeout"
|
|
209
209
|
});
|
|
210
|
-
const metadata = yield* read(reference, deadline).pipe(Effect.timeoutOrElse({
|
|
210
|
+
const metadata = yield* read(reference, deadline).pipe(Effect.withTracerEnabled(false), Effect.timeoutOrElse({
|
|
211
211
|
duration: remaining,
|
|
212
212
|
orElse: () => Effect.fail(SessionError.make({
|
|
213
213
|
operation: "session-wait",
|
|
@@ -222,7 +222,7 @@ var BrowserbaseSessions = class BrowserbaseSessions extends Context.Service()("e
|
|
|
222
222
|
yield* Effect.sleep(Math.max(0, Math.min(bounds.pollIntervalMillis ?? 250, deadline - (yield* now))));
|
|
223
223
|
}
|
|
224
224
|
});
|
|
225
|
-
const logs = Effect.
|
|
225
|
+
const logs = Effect.fnUntraced(function* (reference, options = {}) {
|
|
226
226
|
const ref = yield* validate(reference, "session-logs");
|
|
227
227
|
const raw = yield* client.json("GET", `/v1/sessions/${encodeURIComponent(ref.sessionId)}/logs`).pipe(Effect.mapError((error) => fromClient("session-logs", error)));
|
|
228
228
|
const rows = yield* Schema.decodeUnknownEffect(Schema.Array(ProviderLog).check(Schema.isMaxLength(1e5)))(raw).pipe(Effect.mapError(() => malformed("session-logs")));
|
|
@@ -238,23 +238,23 @@ var BrowserbaseSessions = class BrowserbaseSessions extends Context.Service()("e
|
|
|
238
238
|
...options.includePayloads === true && row.request?.params !== void 0 ? { params: row.request.params } : {},
|
|
239
239
|
...options.includePayloads === true && row.response?.result !== void 0 ? { result: row.response.result } : {}
|
|
240
240
|
}));
|
|
241
|
-
});
|
|
242
|
-
const liveUrls = Effect.
|
|
241
|
+
}, span("BrowserbaseSessions.logs"));
|
|
242
|
+
const liveUrls = Effect.fnUntraced(function* (reference, expiresInSeconds = 300) {
|
|
243
243
|
const ref = yield* validate(reference, "session-live-view");
|
|
244
244
|
return yield* issueLiveUrls(client, ref, expiresInSeconds).pipe(Effect.mapError((error) => fromClient("session-live-view", error)));
|
|
245
|
-
});
|
|
245
|
+
}, span("BrowserbaseSessions.liveUrls"));
|
|
246
246
|
return BrowserbaseSessions.of({
|
|
247
247
|
logs,
|
|
248
248
|
liveUrls,
|
|
249
249
|
retrieve,
|
|
250
250
|
list,
|
|
251
251
|
requestRelease,
|
|
252
|
-
waitForTerminal: (ref, options) => wait(ref, options, false),
|
|
253
|
-
waitUntilRunning: (ref, options) => wait(ref, options, true)
|
|
252
|
+
waitForTerminal: (ref, options) => wait(ref, options, false).pipe(span("BrowserbaseSessions.waitForTerminal")),
|
|
253
|
+
waitUntilRunning: (ref, options) => wait(ref, options, true).pipe(span("BrowserbaseSessions.waitUntilRunning"))
|
|
254
254
|
});
|
|
255
255
|
}));
|
|
256
256
|
};
|
|
257
257
|
//#endregion
|
|
258
258
|
export { issueLiveView as a, SessionWaitOptions as i, SessionListQuery as n, browserRequestFailure as o, SessionLogEntry as r, BrowserbaseSessions as t };
|
|
259
259
|
|
|
260
|
-
//# sourceMappingURL=Sessions-
|
|
260
|
+
//# sourceMappingURL=Sessions-D2H5m6rF.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Sessions-D2H5m6rF.mjs","names":["Trace.span"],"sources":["../src/internal/browser/RequestFailure.ts","../src/internal/browser/LiveView.ts","../src/Sessions.ts"],"sourcesContent":["import { BrowserError, Reasons, type BrowserReason } from \"effect-browser/errors\";\n\nimport type { ClientError } from \"../../Errors.ts\";\n\ntype RequestFailure = Pick<ClientError, \"reason\" | \"outcome\" | \"status\" | \"retryAfterMillis\">;\n\n/** Only control-plane reads reach this bridge, before a modeled browser action dispatches. */\nexport const browserRequestFailure = (\n operation: \"connect\" | \"reconnect\" | \"live-view\",\n error: RequestFailure,\n): BrowserError => {\n const reason = (): BrowserReason => {\n switch (error.reason) {\n case \"configuration\":\n return Reasons.Configuration.make({});\n case \"authorization\":\n return Reasons.Authorization.make({});\n case \"rate-limited\":\n return Reasons.RateLimited.make(\n error.retryAfterMillis === undefined ? {} : { retryAfterMillis: error.retryAfterMillis },\n );\n case \"not-found\":\n return Reasons.NotFound.make({});\n case \"active\":\n return Reasons.Active.make({});\n case \"disabled\":\n return Reasons.Disabled.make({});\n case \"expired\":\n return Reasons.Expired.make({});\n case \"transport\":\n return Reasons.Transport.make(error.status === undefined ? {} : { status: error.status });\n case \"timeout\":\n return Reasons.Timeout.make({});\n case \"malformed\":\n return Reasons.Malformed.make({});\n case \"unsafe-url\":\n return Reasons.UnsafeUrl.make({});\n case \"content-type\":\n return Reasons.ContentType.make({});\n // A control-plane limit carries no measured bound. Do not invent native Limit facts.\n case \"limit\":\n case \"provider\":\n return Reasons.Provider.make(error.status === undefined ? {} : { status: error.status });\n }\n };\n\n return BrowserError.make({\n operation,\n reason: reason(),\n outcome: error.outcome ?? \"undispatched\",\n });\n};\n","import { Effect, Redacted, Schema } from \"effect\";\n\nimport type { BrowserbaseClient } from \"../../Client.ts\";\nimport { ClientError } from \"../../Errors.ts\";\nimport { Identifier, type SessionReference } from \"../../References.ts\";\nimport { browserRequestFailure } from \"./RequestFailure.ts\";\n\nconst LiveUrl = Schema.String.check(\n Schema.isMaxLength(16384),\n Schema.makeFilter((value) => {\n try {\n const url = new URL(value);\n\n return (\n url.protocol === \"https:\" &&\n !url.username &&\n !url.password &&\n (url.hostname === \"browserbase.com\" || url.hostname.endsWith(\".browserbase.com\"))\n );\n } catch {\n return false;\n }\n }),\n);\n\nconst Live = Schema.Struct({\n debuggerFullscreenUrl: LiveUrl,\n pages: Schema.Array(Schema.Struct({ id: Identifier, debuggerFullscreenUrl: LiveUrl })).check(\n Schema.isMaxLength(64),\n ),\n});\n\nexport interface LiveView {\n readonly session: Redacted.Redacted<string>;\n readonly pages: ReadonlyArray<{\n readonly liveViewPageId: string;\n readonly url: Redacted.Redacted<string>;\n }>;\n /** Echo of the requested TTL, not a provider-confirmed expiration time. */\n readonly requestedTtlSeconds: number;\n}\n\n/**\n * These URLs are bearer capabilities: issuing one is an authorization step, not proof that an\n * operator took control. Redaction keeps them out of ordinary logs and model-facing values.\n */\nexport const issueLiveUrls = Effect.fnUntraced(function* (\n client: BrowserbaseClient[\"Service\"],\n reference: SessionReference,\n expiresInSeconds: number,\n) {\n // The pinned SDK documents an optional `expiresIn` with a 21,600 second maximum, but neither\n // it nor the published debug-route schema specifies a provider minimum. One second is this\n // adapter's positive-integer input bound, not a claim that Browserbase will accept or honor it.\n if (!Number.isSafeInteger(expiresInSeconds) || expiresInSeconds < 1 || expiresInSeconds > 21600)\n return yield* ClientError.make({\n operation: \"provider-read\",\n reason: \"configuration\",\n outcome: \"undispatched\",\n });\n if (reference.projectId !== client.projectId)\n return yield* ClientError.make({\n operation: \"provider-read\",\n reason: \"authorization\",\n outcome: \"undispatched\",\n });\n\n const raw = yield* client.json(\n \"GET\",\n `/v1/sessions/${encodeURIComponent(reference.sessionId)}/debug?expiresIn=${expiresInSeconds}`,\n );\n\n const value = yield* Schema.decodeUnknownEffect(Live)(raw).pipe(\n Effect.mapError(() => ClientError.make({ operation: \"provider-read\", reason: \"malformed\" })),\n );\n\n return {\n session: Redacted.make(value.debuggerFullscreenUrl),\n pages: value.pages.map((page) => ({\n liveViewPageId: page.id,\n url: Redacted.make(page.debuggerFullscreenUrl),\n })),\n requestedTtlSeconds: expiresInSeconds,\n } satisfies LiveView;\n});\n\nexport const issueLiveView = (\n client: BrowserbaseClient[\"Service\"],\n reference: SessionReference,\n expiresInSeconds: number,\n) =>\n issueLiveUrls(client, reference, expiresInSeconds).pipe(\n Effect.mapError((error) => browserRequestFailure(\"live-view\", error)),\n );\n","import { Clock, Context, Effect, Layer, Schema } from \"effect\";\n\nimport { BrowserbaseClient } from \"./Client.ts\";\nimport { type ClientError, SessionError } from \"./Errors.ts\";\nimport { issueLiveUrls, type LiveView } from \"./internal/browser/LiveView.ts\";\nimport * as Trace from \"./internal/Trace.ts\";\nexport type { LiveView } from \"./internal/browser/LiveView.ts\";\nimport { SessionReference } from \"./References.ts\";\nimport {\n ProviderSession,\n SessionMetadata,\n SessionStatus,\n isTerminalSessionStatus,\n} from \"./SessionData.ts\";\nexport { SessionMetadata, SessionStatus, isTerminalSessionStatus } from \"./SessionData.ts\";\n\nexport const SessionListQuery = Schema.Struct({\n status: Schema.optionalKey(SessionStatus),\n q: Schema.optionalKey(Schema.NonEmptyString.check(Schema.isMaxLength(2048))),\n});\n\nexport type SessionListQuery = typeof SessionListQuery.Type;\n\nexport const SessionWaitOptions = Schema.Struct({\n timeoutMillis: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 600000 })),\n pollIntervalMillis: Schema.optionalKey(\n Schema.Int.check(Schema.isBetween({ minimum: 25, maximum: 5000 })),\n ),\n});\n\nexport type SessionWaitOptions = typeof SessionWaitOptions.Type;\n\nconst Millis = Schema.Finite;\n\n/**\n * One CDP-level log entry. Protocol payloads are present only when requested: they carry\n * page content, cookies and typed input, so they are host evidence, never model input.\n */\nexport class SessionLogEntry extends Schema.Class<SessionLogEntry>(\"BrowserbaseSessionLogEntry\")({\n method: Schema.String.check(Schema.isMaxLength(256)),\n pageId: Schema.Int,\n frameId: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(256))),\n loaderId: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(256))),\n timestamp: Schema.optionalKey(Millis),\n requestTimestamp: Schema.optionalKey(Millis),\n responseTimestamp: Schema.optionalKey(Millis),\n params: Schema.optionalKey(Schema.Json),\n result: Schema.optionalKey(Schema.Json),\n}) {}\n\nconst ProviderLog = Schema.Struct({\n method: SessionLogEntry.fields.method,\n pageId: Schema.Int,\n sessionId: Schema.String,\n frameId: SessionLogEntry.fields.frameId,\n loaderId: SessionLogEntry.fields.loaderId,\n timestamp: Schema.optionalKey(Millis),\n request: Schema.optionalKey(\n Schema.Struct({\n params: Schema.optionalKey(Schema.Json),\n timestamp: Schema.optionalKey(Millis),\n }),\n ),\n response: Schema.optionalKey(\n Schema.Struct({\n result: Schema.optionalKey(Schema.Json),\n timestamp: Schema.optionalKey(Millis),\n }),\n ),\n});\n\nexport interface SessionLogOptions {\n /** Include CDP `params`/`result` payloads. Off by default; see `SessionLogEntry`. */\n readonly includePayloads?: boolean;\n}\n\nconst now = Clock.monotonicTimeNanos.pipe(Effect.map((value) => Number(value) / 1000000));\n\nconst fromClient = (operation: SessionError[\"operation\"], error: ClientError): SessionError =>\n SessionError.make({\n operation,\n reason: error.reason,\n ...(error.outcome === undefined ? {} : { outcome: error.outcome }),\n ...(error.status === undefined ? {} : { status: error.status }),\n ...(error.retryAfterMillis === undefined ? {} : { retryAfterMillis: error.retryAfterMillis }),\n });\n\nconst malformed = (operation: SessionError[\"operation\"], mutation = false) =>\n SessionError.make({\n operation,\n reason: \"malformed\",\n ...(mutation ? { outcome: \"unknown\" as const } : {}),\n });\n\nconst configuration = (operation: SessionError[\"operation\"]) =>\n SessionError.make({ operation, reason: \"configuration\", outcome: \"undispatched\" });\n\n/** Passive inspection never releases a remote session. Release is a separate explicit mutation. */\nexport class BrowserbaseSessions extends Context.Service<\n BrowserbaseSessions,\n {\n readonly retrieve: (\n reference: SessionReference,\n ) => Effect.Effect<SessionMetadata, SessionError>;\n readonly list: (\n query?: SessionListQuery,\n ) => Effect.Effect<ReadonlyArray<SessionMetadata>, SessionError>;\n readonly requestRelease: (\n reference: SessionReference,\n ) => Effect.Effect<SessionMetadata, SessionError>;\n readonly waitForTerminal: (\n reference: SessionReference,\n options: SessionWaitOptions,\n ) => Effect.Effect<SessionMetadata, SessionError>;\n readonly waitUntilRunning: (\n reference: SessionReference,\n options: SessionWaitOptions,\n ) => Effect.Effect<SessionMetadata, SessionError>;\n /** Session logs, bounded by the 1 MiB control-plane reply limit (`reason: \"limit\"`). */\n readonly logs: (\n reference: SessionReference,\n options?: SessionLogOptions,\n ) => Effect.Effect<ReadonlyArray<SessionLogEntry>, SessionError>;\n /**\n * Redacted Live View URLs for any session in the project, owned or not. Issuing a URL\n * grants view and input access to whoever holds it; it does not pause automation.\n */\n readonly liveUrls: (\n reference: SessionReference,\n expiresInSeconds?: number,\n ) => Effect.Effect<LiveView, SessionError>;\n }\n>()(\"effect-browserbase/Sessions\") {\n static readonly layer: Layer.Layer<BrowserbaseSessions, never, BrowserbaseClient> = Layer.effect(\n BrowserbaseSessions,\n Effect.gen(function* () {\n const client = yield* BrowserbaseClient;\n\n const validate = Effect.fnUntraced(function* (\n reference: SessionReference,\n operation: SessionError[\"operation\"],\n ) {\n const ref = yield* Schema.decodeEffect(SessionReference)(reference, {\n onExcessProperty: \"error\",\n }).pipe(Effect.mapError(() => configuration(operation)));\n\n if (ref.projectId !== client.projectId)\n return yield* SessionError.make({\n operation,\n reason: \"authorization\",\n outcome: \"undispatched\",\n });\n\n return ref;\n });\n\n const decode = Effect.fnUntraced(function* (\n raw: unknown,\n operation: SessionError[\"operation\"],\n expected?: SessionReference,\n mutation: boolean = false,\n ) {\n const value = yield* Schema.decodeUnknownEffect(ProviderSession)(raw).pipe(\n Effect.mapError(() => malformed(operation, mutation)),\n );\n\n if (\n value.projectId !== client.projectId ||\n (expected !== undefined &&\n (value.id !== expected.sessionId || value.projectId !== expected.projectId))\n )\n return yield* malformed(operation, mutation);\n const { id, projectId, ...metadata } = value;\n\n return SessionMetadata.make({\n reference: SessionReference.make({ provider: \"browserbase\", projectId, sessionId: id }),\n ...metadata,\n });\n });\n\n const read = Effect.fnUntraced(function* (reference: SessionReference, deadline?: number) {\n const ref = yield* validate(reference, \"session-retrieve\");\n\n const raw = yield* client\n .json(\"GET\", `/v1/sessions/${encodeURIComponent(ref.sessionId)}`, undefined, deadline)\n .pipe(Effect.mapError((error) => fromClient(\"session-retrieve\", error)));\n\n return yield* decode(raw, \"session-retrieve\", ref);\n });\n\n const retrieve = Effect.fnUntraced(function* (reference: SessionReference) {\n return yield* read(reference);\n }, Trace.span(\"BrowserbaseSessions.retrieve\"));\n\n const list = Effect.fnUntraced(function* (query: SessionListQuery = {}) {\n const checked = yield* Schema.decodeEffect(SessionListQuery)(query, {\n onExcessProperty: \"error\",\n }).pipe(Effect.mapError(() => configuration(\"session-list\")));\n\n const search = new URLSearchParams();\n\n if (checked.status !== undefined) search.set(\"status\", checked.status);\n if (checked.q !== undefined) search.set(\"q\", checked.q);\n\n const raw = yield* client\n .json(\"GET\", `/v1/sessions${search.size === 0 ? \"\" : `?${search}`}`)\n .pipe(Effect.mapError((error) => fromClient(\"session-list\", error)));\n\n const rows = yield* Schema.decodeUnknownEffect(\n Schema.Array(ProviderSession).check(Schema.isMaxLength(1024)),\n )(raw).pipe(Effect.mapError(() => malformed(\"session-list\")));\n\n if (new Set(rows.map((row) => row.id)).size !== rows.length)\n return yield* malformed(\"session-list\");\n const output: SessionMetadata[] = [];\n\n for (const row of rows) output.push(yield* decode(row, \"session-list\"));\n\n return output;\n }, Trace.span(\"BrowserbaseSessions.list\"));\n\n const requestRelease = Effect.fnUntraced(function* (reference: SessionReference) {\n const ref = yield* validate(reference, \"session-release\");\n\n const raw = yield* client\n .json(\"POST\", `/v1/sessions/${encodeURIComponent(ref.sessionId)}`, {\n projectId: ref.projectId,\n status: \"REQUEST_RELEASE\",\n })\n .pipe(Effect.mapError((error) => fromClient(\"session-release\", error)));\n\n return yield* decode(raw, \"session-release\", ref, true);\n }, Trace.span(\"BrowserbaseSessions.requestRelease\"));\n\n const wait = Effect.fnUntraced(function* (\n reference: SessionReference,\n options: SessionWaitOptions,\n untilRunning: boolean,\n ) {\n const bounds = yield* Schema.decodeEffect(SessionWaitOptions)(options, {\n onExcessProperty: \"error\",\n }).pipe(Effect.mapError(() => configuration(\"session-wait\")));\n\n const deadline = (yield* now) + bounds.timeoutMillis;\n\n for (;;) {\n const remaining = deadline - (yield* now);\n\n if (remaining <= 0)\n return yield* SessionError.make({ operation: \"session-wait\", reason: \"timeout\" });\n\n // The deadline bounds the provider read too, not just sleeps between reads.\n const metadata = yield* read(reference, deadline).pipe(\n Effect.withTracerEnabled(false),\n Effect.timeoutOrElse({\n duration: remaining,\n orElse: () =>\n Effect.fail(SessionError.make({ operation: \"session-wait\", reason: \"timeout\" })),\n }),\n );\n\n if (\n untilRunning ? metadata.status === \"RUNNING\" : isTerminalSessionStatus(metadata.status)\n )\n return metadata;\n if (untilRunning && isTerminalSessionStatus(metadata.status))\n return yield* SessionError.make({ operation: \"session-wait\", reason: \"expired\" });\n yield* Effect.sleep(\n Math.max(0, Math.min(bounds.pollIntervalMillis ?? 250, deadline - (yield* now))),\n );\n }\n });\n\n const logs = Effect.fnUntraced(function* (\n reference: SessionReference,\n options: SessionLogOptions = {},\n ) {\n const ref = yield* validate(reference, \"session-logs\");\n\n const raw = yield* client\n .json(\"GET\", `/v1/sessions/${encodeURIComponent(ref.sessionId)}/logs`)\n .pipe(Effect.mapError((error) => fromClient(\"session-logs\", error)));\n\n const rows = yield* Schema.decodeUnknownEffect(\n Schema.Array(ProviderLog).check(Schema.isMaxLength(100_000)),\n )(raw).pipe(Effect.mapError(() => malformed(\"session-logs\")));\n\n if (rows.some((row) => row.sessionId !== ref.sessionId))\n return yield* malformed(\"session-logs\");\n\n return rows.map((row) =>\n SessionLogEntry.make({\n method: row.method,\n pageId: row.pageId,\n ...(row.frameId === undefined ? {} : { frameId: row.frameId }),\n ...(row.loaderId === undefined ? {} : { loaderId: row.loaderId }),\n ...(row.timestamp === undefined ? {} : { timestamp: row.timestamp }),\n ...(row.request?.timestamp === undefined\n ? {}\n : { requestTimestamp: row.request.timestamp }),\n ...(row.response?.timestamp === undefined\n ? {}\n : { responseTimestamp: row.response.timestamp }),\n ...(options.includePayloads === true && row.request?.params !== undefined\n ? { params: row.request.params }\n : {}),\n ...(options.includePayloads === true && row.response?.result !== undefined\n ? { result: row.response.result }\n : {}),\n }),\n );\n }, Trace.span(\"BrowserbaseSessions.logs\"));\n\n const liveUrls = Effect.fnUntraced(function* (\n reference: SessionReference,\n expiresInSeconds: number = 300,\n ) {\n const ref = yield* validate(reference, \"session-live-view\");\n\n return yield* issueLiveUrls(client, ref, expiresInSeconds).pipe(\n Effect.mapError((error) => fromClient(\"session-live-view\", error)),\n );\n }, Trace.span(\"BrowserbaseSessions.liveUrls\"));\n\n return BrowserbaseSessions.of({\n logs,\n liveUrls,\n retrieve,\n list,\n requestRelease,\n waitForTerminal: (ref, options) =>\n wait(ref, options, false).pipe(Trace.span(\"BrowserbaseSessions.waitForTerminal\")),\n waitUntilRunning: (ref, options) =>\n wait(ref, options, true).pipe(Trace.span(\"BrowserbaseSessions.waitUntilRunning\")),\n });\n }),\n );\n}\n"],"mappings":"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"}
|
package/dist/Sessions.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { SessionMetadata, SessionStatus, isTerminalSessionStatus } from "./SessionData.mjs";
|
|
2
|
-
import { i as SessionWaitOptions, n as SessionListQuery, r as SessionLogEntry, t as BrowserbaseSessions } from "./Sessions-
|
|
2
|
+
import { i as SessionWaitOptions, n as SessionListQuery, r as SessionLogEntry, t as BrowserbaseSessions } from "./Sessions-D2H5m6rF.mjs";
|
|
3
3
|
export { BrowserbaseSessions, SessionListQuery, SessionLogEntry, SessionMetadata, SessionStatus, SessionWaitOptions, isTerminalSessionStatus };
|
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-
|
|
7
|
+
import { t as BrowserbaseBrowser } from "./Browser-ByrWJ0ss.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/dist/Uploads.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FileError } from "./Errors.mjs";
|
|
2
|
+
import { r as span, t as BrowserbaseClient } from "./Client-BEC4Q8ZS.mjs";
|
|
2
3
|
import { RemoteFilePath, SafeFilename, UploadReceipt } from "./Transfers.mjs";
|
|
3
|
-
import { t as
|
|
4
|
-
import { t as BrowserbaseSessions } from "./Sessions-BUoyPcPJ.mjs";
|
|
4
|
+
import { t as BrowserbaseSessions } from "./Sessions-D2H5m6rF.mjs";
|
|
5
5
|
import { n as recordIssuedUpload } from "./Issued-DejqoMYL.mjs";
|
|
6
6
|
import { Context, Effect, Layer, Schema } from "effect";
|
|
7
7
|
//#region src/Uploads.ts
|
|
@@ -56,7 +56,7 @@ var BrowserbaseUploads = class BrowserbaseUploads extends Context.Service()("eff
|
|
|
56
56
|
static layer = Layer.effect(BrowserbaseUploads, Effect.gen(function* () {
|
|
57
57
|
const client = yield* BrowserbaseClient;
|
|
58
58
|
const sessions = yield* BrowserbaseSessions;
|
|
59
|
-
const create = Effect.
|
|
59
|
+
const create = Effect.fnUntraced(function* (reference, file) {
|
|
60
60
|
const { bytes, ...rest } = file;
|
|
61
61
|
const value = yield* Schema.decodeEffect(UploadOptions)(rest, { onExcessProperty: "error" }).pipe(Effect.mapError(() => failure("upload", "configuration")));
|
|
62
62
|
if (!(bytes instanceof Uint8Array)) return yield* failure("upload", "configuration");
|
|
@@ -95,7 +95,7 @@ var BrowserbaseUploads = class BrowserbaseUploads extends Context.Service()("eff
|
|
|
95
95
|
remotePath
|
|
96
96
|
});
|
|
97
97
|
return receipt;
|
|
98
|
-
});
|
|
98
|
+
}, span("BrowserbaseUploads.create"));
|
|
99
99
|
return BrowserbaseUploads.of({ create });
|
|
100
100
|
}));
|
|
101
101
|
};
|
package/dist/Uploads.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Uploads.mjs","names":[],"sources":["../src/Uploads.ts"],"sourcesContent":["import { Context, Effect, Layer, Schema } from \"effect\";\n\nimport { BrowserbaseClient } from \"./Client.ts\";\nimport { type ClientError, FileError } from \"./Errors.ts\";\nimport { recordIssuedUpload } from \"./internal/upload/Issued.ts\";\nimport type { SessionReference } from \"./References.ts\";\nimport { BrowserbaseSessions } from \"./Sessions.ts\";\nimport { RemoteFilePath, SafeFilename, UploadReceipt } from \"./Transfers.ts\";\n\n/** The provider's documented per-file ceiling for a session upload. */\nconst MAX_UPLOAD_BYTES = 512 * 1024 * 1024;\n\nconst MediaType = Schema.NonEmptyString.check(\n Schema.isMaxLength(128),\n Schema.isPattern(/^[a-z0-9][a-z0-9!#$&^_+.-]*\\/[a-z0-9][a-z0-9!#$&^_+.-]*$/),\n);\n\nconst UploadOptions = Schema.Struct({\n filename: SafeFilename,\n mediaType: MediaType,\n maxBytes: Schema.optionalKey(\n Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: MAX_UPLOAD_BYTES })),\n ),\n timeoutMillis: Schema.optionalKey(\n Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 600_000 })),\n ),\n});\n\n/**\n * Only fields this package can validate are carried forward. `path` is the provider's own\n * remote location for the stored file; when the response omits it, the receipt says so\n * instead of inventing one, and attachment by path is refused rather than guessed.\n */\n/**\n * Where the provider places session uploads inside the remote browser. Observed against the\n * provider on 21 September 2026 and documented at\n * https://docs.browserbase.com/platform/browser/files/uploads.md; the create reply does not\n * return it.\n */\nconst UPLOAD_DIRECTORY = \"/tmp/.uploads\";\n\nconst ProviderUpload = Schema.Struct({\n message: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(1024))),\n path: Schema.optionalKey(RemoteFilePath),\n});\n\nexport interface UploadFile {\n readonly filename: string;\n readonly mediaType: string;\n readonly bytes: Uint8Array;\n readonly maxBytes?: number;\n readonly timeoutMillis?: number;\n}\n\nconst failure = (operation: FileError[\"operation\"], reason: FileError[\"reason\"]) =>\n FileError.make({ operation, reason, outcome: \"undispatched\" });\n\nconst fromClient = (operation: FileError[\"operation\"]) => (error: ClientError) =>\n FileError.make({\n operation,\n reason: error.reason,\n ...(error.outcome === undefined ? {} : { outcome: error.outcome }),\n ...(error.status === undefined ? {} : { status: error.status }),\n ...(error.retryAfterMillis === undefined ? {} : { retryAfterMillis: error.retryAfterMillis }),\n });\n\n/**\n * A session upload places bytes where the remote browser can already reach them. It is the\n * large-file half of file selection; small in-memory selection needs no provisioning at all.\n */\nexport class BrowserbaseUploads extends Context.Service<\n BrowserbaseUploads,\n {\n readonly create: (\n reference: SessionReference,\n file: UploadFile,\n ) => Effect.Effect<UploadReceipt, FileError>;\n }\n>()(\"effect-browserbase/Uploads\") {\n static readonly layer: Layer.Layer<\n BrowserbaseUploads,\n never,\n BrowserbaseClient | BrowserbaseSessions\n > = Layer.effect(\n BrowserbaseUploads,\n Effect.gen(function* () {\n const client = yield* BrowserbaseClient;\n const sessions = yield* BrowserbaseSessions;\n\n const create = Effect.
|
|
1
|
+
{"version":3,"file":"Uploads.mjs","names":["Trace.span"],"sources":["../src/Uploads.ts"],"sourcesContent":["import { Context, Effect, Layer, Schema } from \"effect\";\n\nimport { BrowserbaseClient } from \"./Client.ts\";\nimport { type ClientError, FileError } from \"./Errors.ts\";\nimport * as Trace from \"./internal/Trace.ts\";\nimport { recordIssuedUpload } from \"./internal/upload/Issued.ts\";\nimport type { SessionReference } from \"./References.ts\";\nimport { BrowserbaseSessions } from \"./Sessions.ts\";\nimport { RemoteFilePath, SafeFilename, UploadReceipt } from \"./Transfers.ts\";\n\n/** The provider's documented per-file ceiling for a session upload. */\nconst MAX_UPLOAD_BYTES = 512 * 1024 * 1024;\n\nconst MediaType = Schema.NonEmptyString.check(\n Schema.isMaxLength(128),\n Schema.isPattern(/^[a-z0-9][a-z0-9!#$&^_+.-]*\\/[a-z0-9][a-z0-9!#$&^_+.-]*$/),\n);\n\nconst UploadOptions = Schema.Struct({\n filename: SafeFilename,\n mediaType: MediaType,\n maxBytes: Schema.optionalKey(\n Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: MAX_UPLOAD_BYTES })),\n ),\n timeoutMillis: Schema.optionalKey(\n Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 600_000 })),\n ),\n});\n\n/**\n * Only fields this package can validate are carried forward. `path` is the provider's own\n * remote location for the stored file; when the response omits it, the receipt says so\n * instead of inventing one, and attachment by path is refused rather than guessed.\n */\n/**\n * Where the provider places session uploads inside the remote browser. Observed against the\n * provider on 21 September 2026 and documented at\n * https://docs.browserbase.com/platform/browser/files/uploads.md; the create reply does not\n * return it.\n */\nconst UPLOAD_DIRECTORY = \"/tmp/.uploads\";\n\nconst ProviderUpload = Schema.Struct({\n message: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(1024))),\n path: Schema.optionalKey(RemoteFilePath),\n});\n\nexport interface UploadFile {\n readonly filename: string;\n readonly mediaType: string;\n readonly bytes: Uint8Array;\n readonly maxBytes?: number;\n readonly timeoutMillis?: number;\n}\n\nconst failure = (operation: FileError[\"operation\"], reason: FileError[\"reason\"]) =>\n FileError.make({ operation, reason, outcome: \"undispatched\" });\n\nconst fromClient = (operation: FileError[\"operation\"]) => (error: ClientError) =>\n FileError.make({\n operation,\n reason: error.reason,\n ...(error.outcome === undefined ? {} : { outcome: error.outcome }),\n ...(error.status === undefined ? {} : { status: error.status }),\n ...(error.retryAfterMillis === undefined ? {} : { retryAfterMillis: error.retryAfterMillis }),\n });\n\n/**\n * A session upload places bytes where the remote browser can already reach them. It is the\n * large-file half of file selection; small in-memory selection needs no provisioning at all.\n */\nexport class BrowserbaseUploads extends Context.Service<\n BrowserbaseUploads,\n {\n readonly create: (\n reference: SessionReference,\n file: UploadFile,\n ) => Effect.Effect<UploadReceipt, FileError>;\n }\n>()(\"effect-browserbase/Uploads\") {\n static readonly layer: Layer.Layer<\n BrowserbaseUploads,\n never,\n BrowserbaseClient | BrowserbaseSessions\n > = Layer.effect(\n BrowserbaseUploads,\n Effect.gen(function* () {\n const client = yield* BrowserbaseClient;\n const sessions = yield* BrowserbaseSessions;\n\n const create = Effect.fnUntraced(function* (reference: SessionReference, file: UploadFile) {\n const { bytes, ...rest } = file;\n\n const value = yield* Schema.decodeEffect(UploadOptions)(rest, {\n onExcessProperty: \"error\",\n }).pipe(Effect.mapError(() => failure(\"upload\", \"configuration\")));\n\n if (!(bytes instanceof Uint8Array)) return yield* failure(\"upload\", \"configuration\");\n const maxBytes = value.maxBytes ?? MAX_UPLOAD_BYTES;\n\n if (bytes.byteLength < 1 || bytes.byteLength > maxBytes)\n return yield* failure(\"upload\", \"limit\");\n\n // The exact owning session admits the upload; a terminal session cannot receive files.\n const state = yield* sessions\n .retrieve(reference)\n .pipe(\n Effect.mapError((error) =>\n FileError.make({ operation: \"upload\", reason: error.reason }),\n ),\n );\n\n if (state.status !== \"RUNNING\") return yield* failure(\"upload\", \"expired\");\n\n // Send the same immutable bytes that were measured a moment ago.\n const owned = new Uint8Array(bytes);\n\n const raw = yield* client\n .upload(\n `/v1/sessions/${encodeURIComponent(state.reference.sessionId)}/uploads`,\n {\n field: \"file\",\n filename: value.filename,\n mediaType: value.mediaType,\n bytes: owned,\n },\n {\n maxBytes,\n ...(value.timeoutMillis === undefined ? {} : { timeoutMillis: value.timeoutMillis }),\n },\n )\n .pipe(Effect.mapError(fromClient(\"upload\")));\n\n const acknowledged = yield* Schema.decodeUnknownEffect(ProviderUpload)(raw).pipe(\n Effect.mapError(() =>\n FileError.make({ operation: \"upload\", reason: \"malformed\", outcome: \"unknown\" }),\n ),\n );\n\n // The provider's reply carries only a message; its documented upload location is a\n // fixed directory keyed by the part's filename, which was validated above. A path the\n // provider does return still wins, and was checked for traversal when decoded.\n const remotePath = acknowledged.path ?? `${UPLOAD_DIRECTORY}/${value.filename}`;\n\n const receipt = UploadReceipt.make({\n reference: state.reference,\n filename: value.filename,\n bytes: owned.byteLength,\n remotePath,\n ...(acknowledged.message === undefined ? {} : { acknowledgement: acknowledged.message }),\n });\n\n recordIssuedUpload(receipt, { reference: state.reference, remotePath });\n\n return receipt;\n }, Trace.span(\"BrowserbaseUploads.create\"));\n\n return BrowserbaseUploads.of({ create });\n }),\n );\n}\n"],"mappings":"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"}
|
package/dist/Webhooks.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Identifier } from "./References.mjs";
|
|
2
2
|
import { PlatformError } from "./Errors.mjs";
|
|
3
|
-
import { t as BrowserbaseClient } from "./Client-
|
|
4
|
-
import { t as resource } from "./Resource-
|
|
3
|
+
import { r as span, t as BrowserbaseClient } from "./Client-BEC4Q8ZS.mjs";
|
|
4
|
+
import { t as resource } from "./Resource-J7Kkk5mu.mjs";
|
|
5
5
|
import { Context, Effect, Layer, Redacted, Schema } from "effect";
|
|
6
6
|
//#region src/Webhooks.ts
|
|
7
7
|
const Timestamp = Schema.String.check(Schema.isMaxLength(64));
|
|
@@ -77,7 +77,7 @@ var BrowserbaseWebhooks = class BrowserbaseWebhooks extends Context.Service()("e
|
|
|
77
77
|
});
|
|
78
78
|
});
|
|
79
79
|
const path = (id) => `/v1/webhooks/${api.segment(id)}`;
|
|
80
|
-
const create = Effect.
|
|
80
|
+
const create = Effect.fnUntraced(function* (settings) {
|
|
81
81
|
const value = yield* api.input(WebhookSettings, settings, "webhook-create");
|
|
82
82
|
const { secret, ...webhook } = yield* api.request("POST", "/v1/webhooks", Schema.Struct({
|
|
83
83
|
...ProviderWebhook.fields,
|
|
@@ -87,37 +87,37 @@ var BrowserbaseWebhooks = class BrowserbaseWebhooks extends Context.Service()("e
|
|
|
87
87
|
webhook: yield* decode("webhook-create", true)(webhook),
|
|
88
88
|
secret: Redacted.make(secret)
|
|
89
89
|
};
|
|
90
|
-
});
|
|
91
|
-
const list = Effect.
|
|
90
|
+
}, span("BrowserbaseWebhooks.create"));
|
|
91
|
+
const list = Effect.fnUntraced(function* (query = {}) {
|
|
92
92
|
const value = yield* api.input(WebhookListQuery, query, "webhook-list");
|
|
93
93
|
const page = yield* api.request("GET", `/v1/webhooks${api.query(value)}`, Page, "webhook-list");
|
|
94
94
|
return {
|
|
95
95
|
webhooks: yield* Effect.forEach(page.data, decode("webhook-list", false)),
|
|
96
96
|
nextCursor: page.nextCursor ?? void 0
|
|
97
97
|
};
|
|
98
|
-
});
|
|
99
|
-
const retrieve = Effect.
|
|
98
|
+
}, span("BrowserbaseWebhooks.list"));
|
|
99
|
+
const retrieve = Effect.fnUntraced(function* (webhookId) {
|
|
100
100
|
const id = yield* api.input(Identifier, webhookId, "webhook-retrieve");
|
|
101
101
|
const value = yield* api.request("GET", path(id), ProviderWebhook, "webhook-retrieve");
|
|
102
102
|
return yield* decode("webhook-retrieve", false, id)(value);
|
|
103
|
-
});
|
|
104
|
-
const update = Effect.
|
|
103
|
+
}, span("BrowserbaseWebhooks.retrieve"));
|
|
104
|
+
const update = Effect.fnUntraced(function* (webhookId, changes) {
|
|
105
105
|
const id = yield* api.input(Identifier, webhookId, "webhook-update");
|
|
106
106
|
const value = yield* api.input(WebhookUpdate, changes, "webhook-update");
|
|
107
107
|
if (value.endpoint === void 0 && value.eventTypes === void 0) return yield* api.configuration("webhook-update");
|
|
108
108
|
const updated = yield* api.request("PATCH", path(id), ProviderWebhook, "webhook-update", value);
|
|
109
109
|
return yield* decode("webhook-update", true, id)(updated);
|
|
110
|
-
});
|
|
111
|
-
const remove = Effect.
|
|
110
|
+
}, span("BrowserbaseWebhooks.update"));
|
|
111
|
+
const remove = Effect.fnUntraced(function* (webhookId) {
|
|
112
112
|
const id = yield* api.input(Identifier, webhookId, "webhook-delete");
|
|
113
113
|
yield* api.remove(path(id), "webhook-delete");
|
|
114
|
-
});
|
|
115
|
-
const rotateSecret = Effect.
|
|
114
|
+
}, span("BrowserbaseWebhooks.delete"));
|
|
115
|
+
const rotateSecret = Effect.fnUntraced(function* (webhookId, options = {}) {
|
|
116
116
|
const id = yield* api.input(Identifier, webhookId, "webhook-rotate-secret");
|
|
117
117
|
const value = yield* api.input(Schema.Struct({ revokeImmediately: Schema.optionalKey(Schema.Boolean) }), options, "webhook-rotate-secret");
|
|
118
118
|
const rotated = yield* api.request("POST", `${path(id)}/secret`, Schema.Struct({ secret: Secret }), "webhook-rotate-secret", value);
|
|
119
119
|
return Redacted.make(rotated.secret);
|
|
120
|
-
});
|
|
120
|
+
}, span("BrowserbaseWebhooks.rotateSecret"));
|
|
121
121
|
return BrowserbaseWebhooks.of({
|
|
122
122
|
create,
|
|
123
123
|
list,
|