effect-browserbase 0.1.0-beta.102

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +441 -0
  3. package/dist/Account.d.mts +34 -0
  4. package/dist/Account.mjs +41 -0
  5. package/dist/Account.mjs.map +1 -0
  6. package/dist/Acquisition-WBafHwXH.mjs +280 -0
  7. package/dist/Acquisition-WBafHwXH.mjs.map +1 -0
  8. package/dist/Agents.d.mts +156 -0
  9. package/dist/Agents.mjs +307 -0
  10. package/dist/Agents.mjs.map +1 -0
  11. package/dist/Allocation.d.mts +99 -0
  12. package/dist/Allocation.mjs +29 -0
  13. package/dist/Allocation.mjs.map +1 -0
  14. package/dist/Association-CEps4hYP.mjs +10 -0
  15. package/dist/Association-CEps4hYP.mjs.map +1 -0
  16. package/dist/Authorization-Ll5f_XNM.mjs +12 -0
  17. package/dist/Authorization-Ll5f_XNM.mjs.map +1 -0
  18. package/dist/Bootstrap-BXuzZojd.mjs +194 -0
  19. package/dist/Bootstrap-BXuzZojd.mjs.map +1 -0
  20. package/dist/Bootstrap-m7lHgj0D.d.mts +177 -0
  21. package/dist/Bootstrap.d.mts +2 -0
  22. package/dist/Bootstrap.mjs +2 -0
  23. package/dist/Browser-joE4Zgys.mjs +1557 -0
  24. package/dist/Browser-joE4Zgys.mjs.map +1 -0
  25. package/dist/Browser.d.mts +195 -0
  26. package/dist/Browser.mjs +2 -0
  27. package/dist/BrowserBinding-qbQA6JhH.mjs +2452 -0
  28. package/dist/BrowserBinding-qbQA6JhH.mjs.map +1 -0
  29. package/dist/BrowserBinding.d.mts +40 -0
  30. package/dist/BrowserBinding.mjs +2 -0
  31. package/dist/BrowserData-LpcAuAub.d.mts +369 -0
  32. package/dist/BrowserData.d.mts +2 -0
  33. package/dist/BrowserData.mjs +442 -0
  34. package/dist/BrowserData.mjs.map +1 -0
  35. package/dist/Capture-CZJPuD7b.mjs +532 -0
  36. package/dist/Capture-CZJPuD7b.mjs.map +1 -0
  37. package/dist/Capture-Dr5MkIJb.d.mts +125 -0
  38. package/dist/Capture.d.mts +2 -0
  39. package/dist/Capture.mjs +2 -0
  40. package/dist/Certificates.d.mts +35 -0
  41. package/dist/Certificates.mjs +90 -0
  42. package/dist/Certificates.mjs.map +1 -0
  43. package/dist/Cleanup-G2YpTCuU.d.mts +24 -0
  44. package/dist/Cleanup.d.mts +2 -0
  45. package/dist/Cleanup.mjs +48 -0
  46. package/dist/Cleanup.mjs.map +1 -0
  47. package/dist/Client-Ca0zSg1n.d.mts +53 -0
  48. package/dist/Client-D1_xYM9o.mjs +424 -0
  49. package/dist/Client-D1_xYM9o.mjs.map +1 -0
  50. package/dist/Client.d.mts +2 -0
  51. package/dist/Client.mjs +2 -0
  52. package/dist/ContextCoordination.d.mts +16 -0
  53. package/dist/ContextCoordination.mjs +67 -0
  54. package/dist/ContextCoordination.mjs.map +1 -0
  55. package/dist/ContextWriter-BrQmoXRg.mjs +187 -0
  56. package/dist/ContextWriter-BrQmoXRg.mjs.map +1 -0
  57. package/dist/Contexts.d.mts +32 -0
  58. package/dist/Contexts.mjs +103 -0
  59. package/dist/Contexts.mjs.map +1 -0
  60. package/dist/Deadline-CrViaogr.mjs +13 -0
  61. package/dist/Deadline-CrViaogr.mjs.map +1 -0
  62. package/dist/Downloads.d.mts +44 -0
  63. package/dist/Downloads.mjs +142 -0
  64. package/dist/Downloads.mjs.map +1 -0
  65. package/dist/Errors.d.mts +123 -0
  66. package/dist/Errors.mjs +329 -0
  67. package/dist/Errors.mjs.map +1 -0
  68. package/dist/Extensions-ClZbYb1H.mjs +237 -0
  69. package/dist/Extensions-ClZbYb1H.mjs.map +1 -0
  70. package/dist/Extensions.d.mts +44 -0
  71. package/dist/Extensions.mjs +2 -0
  72. package/dist/Functions.d.mts +227 -0
  73. package/dist/Functions.mjs +332 -0
  74. package/dist/Functions.mjs.map +1 -0
  75. package/dist/Images-DgscEfSf.mjs +127 -0
  76. package/dist/Images-DgscEfSf.mjs.map +1 -0
  77. package/dist/Issued-DejqoMYL.mjs +15 -0
  78. package/dist/Issued-DejqoMYL.mjs.map +1 -0
  79. package/dist/Launch-BHcAEq05.mjs +111 -0
  80. package/dist/Launch-BHcAEq05.mjs.map +1 -0
  81. package/dist/Launch-C8CfaYxb.d.mts +132 -0
  82. package/dist/Launch.d.mts +2 -0
  83. package/dist/Launch.mjs +105 -0
  84. package/dist/Launch.mjs.map +1 -0
  85. package/dist/PageControl.d.mts +16 -0
  86. package/dist/PageControl.mjs +36 -0
  87. package/dist/PageControl.mjs.map +1 -0
  88. package/dist/PageControlAssociation-DabEg5AR.mjs +10 -0
  89. package/dist/PageControlAssociation-DabEg5AR.mjs.map +1 -0
  90. package/dist/PageFetch.d.mts +40 -0
  91. package/dist/PageFetch.mjs +64 -0
  92. package/dist/PageFetch.mjs.map +1 -0
  93. package/dist/Projects.d.mts +39 -0
  94. package/dist/Projects.mjs +71 -0
  95. package/dist/Projects.mjs.map +1 -0
  96. package/dist/Recordings.d.mts +28 -0
  97. package/dist/Recordings.mjs +131 -0
  98. package/dist/Recordings.mjs.map +1 -0
  99. package/dist/References-URDAtapt.d.mts +35 -0
  100. package/dist/References.d.mts +2 -0
  101. package/dist/References.mjs +41 -0
  102. package/dist/References.mjs.map +1 -0
  103. package/dist/Replays.d.mts +28 -0
  104. package/dist/Replays.mjs +109 -0
  105. package/dist/Replays.mjs.map +1 -0
  106. package/dist/Resource-DBksC4zB.mjs +50 -0
  107. package/dist/Resource-DBksC4zB.mjs.map +1 -0
  108. package/dist/Search.d.mts +38 -0
  109. package/dist/Search.mjs +53 -0
  110. package/dist/Search.mjs.map +1 -0
  111. package/dist/SessionData-DRKcKCqw.d.mts +39 -0
  112. package/dist/SessionData.d.mts +2 -0
  113. package/dist/SessionData.mjs +55 -0
  114. package/dist/SessionData.mjs.map +1 -0
  115. package/dist/Sessions-B8E4kMxo.d.mts +68 -0
  116. package/dist/Sessions-CtbseWEh.mjs +244 -0
  117. package/dist/Sessions-CtbseWEh.mjs.map +1 -0
  118. package/dist/Sessions.d.mts +3 -0
  119. package/dist/Sessions.mjs +3 -0
  120. package/dist/TransferPolicy-DQ06i7SZ.mjs +25 -0
  121. package/dist/TransferPolicy-DQ06i7SZ.mjs.map +1 -0
  122. package/dist/Transfers-Czv5IZzJ.d.mts +76 -0
  123. package/dist/Transfers.d.mts +2 -0
  124. package/dist/Transfers.mjs +101 -0
  125. package/dist/Transfers.mjs.map +1 -0
  126. package/dist/Uploads.d.mts +29 -0
  127. package/dist/Uploads.mjs +107 -0
  128. package/dist/Uploads.mjs.map +1 -0
  129. package/dist/Webhooks.d.mts +60 -0
  130. package/dist/Webhooks.mjs +143 -0
  131. package/dist/Webhooks.mjs.map +1 -0
  132. package/dist/WriterFacts-osvYAsIx.d.mts +61 -0
  133. package/dist/index.d.mts +30 -0
  134. package/dist/index.mjs +30 -0
  135. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  136. package/package.json +163 -0
@@ -0,0 +1,187 @@
1
+ import { AllocationAttempt, ContextReference, SessionReference } from "./References.mjs";
2
+ import { ContextError } from "./Errors.mjs";
3
+ import { CleanupResult } from "./Cleanup.mjs";
4
+ import { Effect, Schema } from "effect";
5
+ //#region src/internal/session/WriterFacts.ts
6
+ /**
7
+ * The writer vocabulary both the public coordination entry point and the permit
8
+ * implementation need. Keeping it here leaves one direction of dependency:
9
+ * `ContextCoordination` and `ContextWriter` both read this module, never each other.
10
+ */
11
+ const PersistenceEvidence = Schema.Union([
12
+ Schema.Struct({ _tag: Schema.Literal("NotRequested") }),
13
+ Schema.Struct({
14
+ _tag: Schema.Literal("Unconfirmed"),
15
+ reason: Schema.Literals([
16
+ "writer-active",
17
+ "writer-unknown",
18
+ "flush-unacknowledged"
19
+ ])
20
+ }),
21
+ Schema.Struct({
22
+ _tag: Schema.Literal("Observed"),
23
+ method: Schema.Literal("consumer-readback"),
24
+ observedAtMillis: Schema.Finite
25
+ })
26
+ ]);
27
+ var WriterAttemptFacts = class extends Schema.Class("BrowserbaseWriterAttemptFacts")({
28
+ attempt: AllocationAttempt,
29
+ session: Schema.optionalKey(SessionReference),
30
+ state: Schema.Literals([
31
+ "admitted",
32
+ "rejected",
33
+ "unknown",
34
+ "terminal"
35
+ ]),
36
+ cleanup: Schema.optionalKey(CleanupResult)
37
+ }) {};
38
+ var WriterSettlementFacts = class extends Schema.Class("BrowserbaseWriterSettlementFacts")({
39
+ reference: ContextReference,
40
+ attempts: Schema.Array(WriterAttemptFacts).check(Schema.isMaxLength(64)),
41
+ persistence: PersistenceEvidence,
42
+ disposition: Schema.Literals(["release", "quarantine"])
43
+ }) {};
44
+ //#endregion
45
+ //#region src/internal/session/ContextWriter.ts
46
+ const authentic = /* @__PURE__ */ new WeakMap();
47
+ const active = /* @__PURE__ */ new Map();
48
+ const key = (ref) => `${ref.projectId}/${ref.contextId}`;
49
+ const isContextWriterBusy = (ref) => active.has(key(ref));
50
+ const makeContextWriterPermit = (reference) => Effect.suspend(() => {
51
+ if (active.has(key(reference)) || active.size >= 2048) return Effect.fail(ContextError.make({
52
+ operation: "writer",
53
+ reason: "active",
54
+ outcome: "undispatched"
55
+ }));
56
+ const owned = Object.freeze(reference);
57
+ const attempts = /* @__PURE__ */ new Map();
58
+ let closed = false, quarantined = false;
59
+ let persistence = { _tag: "NotRequested" };
60
+ const unknown = () => {
61
+ quarantined = true;
62
+ persistence = {
63
+ _tag: "Unconfirmed",
64
+ reason: "writer-unknown"
65
+ };
66
+ };
67
+ const noActive = () => [...attempts.values()].every((entry) => entry.state === "rejected" || entry.state === "terminal");
68
+ const permit = {
69
+ _tag: "ContextWriterPermit",
70
+ reference: owned,
71
+ recordAttempt: (attempt) => Effect.suspend(() => {
72
+ if (closed || quarantined || !noActive() || attempt.projectId !== owned.projectId || attempts.size > 0 && persistence._tag === "Unconfirmed") return Effect.fail(ContextError.make({
73
+ operation: "writer-admit",
74
+ reason: "active",
75
+ outcome: "undispatched"
76
+ }));
77
+ if (attempts.has(attempt.attemptId) || attempts.size >= 64) return Effect.fail(ContextError.make({
78
+ operation: "writer-admit",
79
+ reason: "limit",
80
+ outcome: "undispatched"
81
+ }));
82
+ const copy = Object.freeze(attempt);
83
+ attempts.set(copy.attemptId, {
84
+ attempt: copy,
85
+ state: "admitted"
86
+ });
87
+ persistence = {
88
+ _tag: "Unconfirmed",
89
+ reason: "writer-active"
90
+ };
91
+ return Effect.void;
92
+ }),
93
+ recordSession: (attempt, session) => {
94
+ const record = attempts.get(attempt.attemptId);
95
+ if (record === void 0 || record.attempt !== attempt || session.projectId !== owned.projectId || record.session !== void 0 && record.session.sessionId !== session.sessionId) {
96
+ unknown();
97
+ return;
98
+ }
99
+ record.session = Object.freeze(session);
100
+ },
101
+ rejected: (attempt) => {
102
+ const record = attempts.get(attempt.attemptId);
103
+ if (record === void 0 || record.attempt !== attempt || record.session !== void 0) {
104
+ unknown();
105
+ return;
106
+ }
107
+ record.state = "rejected";
108
+ if ([...attempts.values()].every((item) => item.state === "rejected")) persistence = { _tag: "NotRequested" };
109
+ },
110
+ uncertain: (attempt) => {
111
+ const record = attempts.get(attempt.attemptId);
112
+ if (record !== void 0 && record.attempt === attempt) record.state = "unknown";
113
+ unknown();
114
+ },
115
+ completed: (attempt, cleanup) => {
116
+ const record = attempts.get(attempt.attemptId);
117
+ if (record === void 0 || record.attempt !== attempt || cleanup.ownership !== "owned" || record.session === void 0 || record.session.sessionId !== cleanup.reference.sessionId || cleanup.reference.projectId !== owned.projectId) {
118
+ unknown();
119
+ return;
120
+ }
121
+ record.cleanup = cleanup;
122
+ if (cleanup.remote !== "confirmed") {
123
+ record.state = "unknown";
124
+ unknown();
125
+ return;
126
+ }
127
+ record.state = "terminal";
128
+ if (cleanup.observedStatus !== "COMPLETED") {
129
+ unknown();
130
+ return;
131
+ }
132
+ if (!quarantined) persistence = {
133
+ _tag: "Unconfirmed",
134
+ reason: "flush-unacknowledged"
135
+ };
136
+ },
137
+ confirmReadback: (atMillis) => Effect.suspend(() => {
138
+ if (closed || quarantined || !noActive() || !Number.isFinite(atMillis) || attempts.size === 0 || [...attempts.values()].some((entry) => entry.state === "terminal" && entry.cleanup?.observedStatus !== "COMPLETED")) return Effect.fail(ContextError.make({
139
+ operation: "writer-readback",
140
+ reason: "active",
141
+ outcome: "undispatched"
142
+ }));
143
+ persistence = {
144
+ _tag: "Observed",
145
+ method: "consumer-readback",
146
+ observedAtMillis: atMillis
147
+ };
148
+ return Effect.void;
149
+ }),
150
+ quarantine: Effect.sync(unknown),
151
+ snapshot: Effect.sync(() => WriterSettlementFacts.make({
152
+ reference: owned,
153
+ attempts: [...attempts.values()].map((entry) => WriterAttemptFacts.make({
154
+ attempt: entry.attempt,
155
+ state: entry.state,
156
+ ...entry.session === void 0 ? {} : { session: entry.session },
157
+ ...entry.cleanup === void 0 ? {} : { cleanup: entry.cleanup }
158
+ })),
159
+ persistence,
160
+ disposition: quarantined || !noActive() || persistence._tag === "Unconfirmed" ? "quarantine" : "release"
161
+ }))
162
+ };
163
+ Object.freeze(permit);
164
+ authentic.set(permit, permit);
165
+ active.set(key(owned), permit);
166
+ retirement.set(permit, (released) => {
167
+ closed = true;
168
+ if (active.get(key(owned)) !== permit) return;
169
+ if (released) active.delete(key(owned));
170
+ else active.set(key(owned), "quarantined");
171
+ });
172
+ return Effect.succeed(permit);
173
+ });
174
+ const retirement = /* @__PURE__ */ new WeakMap();
175
+ const closeContextWriterPermit = (permit, released) => retirement.get(permit)?.(released);
176
+ const requireContextWriterPermit = (permit, reference) => Effect.suspend(() => {
177
+ const actual = authentic.get(permit);
178
+ return actual !== void 0 && active.get(key(reference)) === actual && actual.reference.contextId === reference.contextId && actual.reference.projectId === reference.projectId ? Effect.succeed(actual) : Effect.fail(ContextError.make({
179
+ operation: "writer-authority",
180
+ reason: "authorization",
181
+ outcome: "undispatched"
182
+ }));
183
+ });
184
+ //#endregion
185
+ export { PersistenceEvidence as a, requireContextWriterPermit as i, isContextWriterBusy as n, WriterAttemptFacts as o, makeContextWriterPermit as r, WriterSettlementFacts as s, closeContextWriterPermit as t };
186
+
187
+ //# sourceMappingURL=ContextWriter-BrQmoXRg.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ContextWriter-BrQmoXRg.mjs","names":[],"sources":["../src/internal/session/WriterFacts.ts","../src/internal/session/ContextWriter.ts"],"sourcesContent":["import type { Effect } from \"effect\";\nimport { Schema } from \"effect\";\n\nimport { CleanupResult } from \"../../Cleanup.ts\";\nimport { AllocationAttempt, ContextReference, SessionReference } from \"../../References.ts\";\n\n/**\n * The writer vocabulary both the public coordination entry point and the permit\n * implementation need. Keeping it here leaves one direction of dependency:\n * `ContextCoordination` and `ContextWriter` both read this module, never each other.\n */\nexport const PersistenceEvidence = Schema.Union([\n Schema.Struct({ _tag: Schema.Literal(\"NotRequested\") }),\n Schema.Struct({\n _tag: Schema.Literal(\"Unconfirmed\"),\n reason: Schema.Literals([\"writer-active\", \"writer-unknown\", \"flush-unacknowledged\"]),\n }),\n Schema.Struct({\n _tag: Schema.Literal(\"Observed\"),\n method: Schema.Literal(\"consumer-readback\"),\n observedAtMillis: Schema.Finite,\n }),\n]);\n\nexport type PersistenceEvidence = typeof PersistenceEvidence.Type;\n\nexport class WriterAttemptFacts extends Schema.Class<WriterAttemptFacts>(\n \"BrowserbaseWriterAttemptFacts\",\n)({\n attempt: AllocationAttempt,\n session: Schema.optionalKey(SessionReference),\n state: Schema.Literals([\"admitted\", \"rejected\", \"unknown\", \"terminal\"]),\n cleanup: Schema.optionalKey(CleanupResult),\n}) {}\n\nexport class WriterSettlementFacts extends Schema.Class<WriterSettlementFacts>(\n \"BrowserbaseWriterSettlementFacts\",\n)({\n reference: ContextReference,\n attempts: Schema.Array(WriterAttemptFacts).check(Schema.isMaxLength(64)),\n persistence: PersistenceEvidence,\n disposition: Schema.Literals([\"release\", \"quarantine\"]),\n}) {}\n\nexport interface WriterLease<E, R> {\n readonly settle: (facts: WriterSettlementFacts) => Effect.Effect<void, E, R>;\n}\n\nexport interface ContextWriterBackend<E, R> {\n readonly acquire: (reference: ContextReference) => Effect.Effect<WriterLease<E, R>, E, R>;\n}\n\nexport interface ContextWriterPermit {\n readonly _tag: \"ContextWriterPermit\";\n readonly reference: ContextReference;\n}\n\nexport interface WriterOptions<A, VerifyE, VerifyR> {\n /** Bounded consumer-controlled readback, not a provider-wide flush acknowledgement. */\n readonly verify?: (value: A) => Effect.Effect<void, VerifyE, VerifyR>;\n readonly settlementTimeoutMillis?: number;\n}\n","import { Effect } from \"effect\";\n\nimport type { CleanupResult } from \"../../Cleanup.ts\";\nimport { ContextError } from \"../../Errors.ts\";\nimport type { AllocationAttempt, ContextReference, SessionReference } from \"../../References.ts\";\nimport {\n type ContextWriterPermit,\n type PersistenceEvidence,\n WriterAttemptFacts,\n WriterSettlementFacts,\n} from \"./WriterFacts.ts\";\n\n/** There is one record per exact allocation attempt, not parallel uncorrelated arrays. */\ninterface AttemptRecord {\n readonly attempt: AllocationAttempt;\n session?: SessionReference;\n state: \"admitted\" | \"rejected\" | \"unknown\" | \"terminal\";\n cleanup?: CleanupResult;\n}\n\nexport interface ContextWriterPermitInternal extends ContextWriterPermit {\n readonly recordAttempt: (attempt: AllocationAttempt) => Effect.Effect<void, ContextError>;\n readonly recordSession: (attempt: AllocationAttempt, reference: SessionReference) => void;\n readonly rejected: (attempt: AllocationAttempt) => void;\n readonly uncertain: (attempt: AllocationAttempt) => void;\n readonly completed: (attempt: AllocationAttempt, cleanup: CleanupResult) => void;\n readonly confirmReadback: (atMillis: number) => Effect.Effect<void, ContextError>;\n readonly quarantine: Effect.Effect<void>;\n readonly snapshot: Effect.Effect<WriterSettlementFacts>;\n}\n\nconst authentic = new WeakMap<ContextWriterPermit, ContextWriterPermitInternal>();\nconst active = new Map<string, ContextWriterPermitInternal | \"quarantined\">();\nconst key = (ref: ContextReference) => `${ref.projectId}/${ref.contextId}`;\n\nexport const isContextWriterBusy = (ref: ContextReference): boolean => active.has(key(ref));\n\nexport const makeContextWriterPermit = (\n reference: ContextReference,\n): Effect.Effect<ContextWriterPermitInternal, ContextError> =>\n Effect.suspend(() => {\n if (active.has(key(reference)) || active.size >= 2048)\n return Effect.fail(\n ContextError.make({ operation: \"writer\", reason: \"active\", outcome: \"undispatched\" }),\n );\n const owned = Object.freeze(reference);\n const attempts = new Map<string, AttemptRecord>();\n\n let closed = false,\n quarantined = false;\n\n let persistence: PersistenceEvidence = { _tag: \"NotRequested\" };\n\n const unknown = () => {\n quarantined = true;\n persistence = { _tag: \"Unconfirmed\", reason: \"writer-unknown\" };\n };\n\n const noActive = () =>\n [...attempts.values()].every(\n (entry) => entry.state === \"rejected\" || entry.state === \"terminal\",\n );\n\n const permit: ContextWriterPermitInternal = {\n _tag: \"ContextWriterPermit\",\n reference: owned,\n recordAttempt: (attempt) =>\n Effect.suspend(() => {\n if (\n closed ||\n quarantined ||\n !noActive() ||\n attempt.projectId !== owned.projectId ||\n (attempts.size > 0 && persistence._tag === \"Unconfirmed\")\n ) {\n return Effect.fail(\n ContextError.make({\n operation: \"writer-admit\",\n reason: \"active\",\n outcome: \"undispatched\",\n }),\n );\n }\n if (attempts.has(attempt.attemptId) || attempts.size >= 64)\n return Effect.fail(\n ContextError.make({\n operation: \"writer-admit\",\n reason: \"limit\",\n outcome: \"undispatched\",\n }),\n );\n const copy = Object.freeze(attempt);\n\n attempts.set(copy.attemptId, { attempt: copy, state: \"admitted\" });\n persistence = { _tag: \"Unconfirmed\", reason: \"writer-active\" };\n\n return Effect.void;\n }),\n recordSession: (attempt, session) => {\n const record = attempts.get(attempt.attemptId);\n\n if (\n record === undefined ||\n record.attempt !== attempt ||\n session.projectId !== owned.projectId ||\n (record.session !== undefined && record.session.sessionId !== session.sessionId)\n ) {\n unknown();\n\n return;\n }\n // Retain identity even when cancellation/quarantine races a late allocation reply.\n record.session = Object.freeze(session);\n },\n rejected: (attempt) => {\n const record = attempts.get(attempt.attemptId);\n\n if (record === undefined || record.attempt !== attempt || record.session !== undefined) {\n unknown();\n\n return;\n }\n record.state = \"rejected\";\n if ([...attempts.values()].every((item) => item.state === \"rejected\"))\n persistence = { _tag: \"NotRequested\" };\n },\n uncertain: (attempt) => {\n const record = attempts.get(attempt.attemptId);\n\n if (record !== undefined && record.attempt === attempt) record.state = \"unknown\";\n unknown();\n },\n completed: (attempt, cleanup) => {\n const record = attempts.get(attempt.attemptId);\n\n if (\n record === undefined ||\n record.attempt !== attempt ||\n cleanup.ownership !== \"owned\" ||\n record.session === undefined ||\n record.session.sessionId !== cleanup.reference.sessionId ||\n cleanup.reference.projectId !== owned.projectId\n ) {\n unknown();\n\n return;\n }\n record.cleanup = cleanup;\n if (cleanup.remote !== \"confirmed\") {\n record.state = \"unknown\";\n unknown();\n\n return;\n }\n record.state = \"terminal\";\n if (cleanup.observedStatus !== \"COMPLETED\") {\n unknown();\n\n return;\n }\n if (!quarantined) persistence = { _tag: \"Unconfirmed\", reason: \"flush-unacknowledged\" };\n },\n confirmReadback: (atMillis) =>\n Effect.suspend(() => {\n if (\n closed ||\n quarantined ||\n !noActive() ||\n !Number.isFinite(atMillis) ||\n attempts.size === 0 ||\n [...attempts.values()].some(\n (entry) =>\n entry.state === \"terminal\" && entry.cleanup?.observedStatus !== \"COMPLETED\",\n )\n ) {\n return Effect.fail(\n ContextError.make({\n operation: \"writer-readback\",\n reason: \"active\",\n outcome: \"undispatched\",\n }),\n );\n }\n persistence = {\n _tag: \"Observed\",\n method: \"consumer-readback\",\n observedAtMillis: atMillis,\n };\n\n return Effect.void;\n }),\n quarantine: Effect.sync(unknown),\n snapshot: Effect.sync(() =>\n WriterSettlementFacts.make({\n reference: owned,\n attempts: [...attempts.values()].map((entry) =>\n WriterAttemptFacts.make({\n attempt: entry.attempt,\n state: entry.state,\n ...(entry.session === undefined ? {} : { session: entry.session }),\n ...(entry.cleanup === undefined ? {} : { cleanup: entry.cleanup }),\n }),\n ),\n persistence,\n disposition:\n quarantined || !noActive() || persistence._tag === \"Unconfirmed\"\n ? \"quarantine\"\n : \"release\",\n }),\n ),\n };\n\n Object.freeze(permit);\n authentic.set(permit, permit);\n active.set(key(owned), permit);\n // Explicit retirement closes admission without losing evidence attached to escaped permits.\n retirement.set(permit, (released) => {\n closed = true;\n if (active.get(key(owned)) !== permit) return;\n if (released) active.delete(key(owned));\n else active.set(key(owned), \"quarantined\");\n });\n\n return Effect.succeed(permit);\n });\n\nconst retirement = new WeakMap<ContextWriterPermitInternal, (released: boolean) => void>();\n\nexport const closeContextWriterPermit = (\n permit: ContextWriterPermitInternal,\n released: boolean,\n): void => retirement.get(permit)?.(released);\n\nexport const requireContextWriterPermit = (\n permit: ContextWriterPermit,\n reference: ContextReference,\n): Effect.Effect<ContextWriterPermitInternal, ContextError> =>\n Effect.suspend(() => {\n const actual = authentic.get(permit);\n\n return actual !== undefined &&\n active.get(key(reference)) === actual &&\n actual.reference.contextId === reference.contextId &&\n actual.reference.projectId === reference.projectId\n ? Effect.succeed(actual)\n : Effect.fail(\n ContextError.make({\n operation: \"writer-authority\",\n reason: \"authorization\",\n outcome: \"undispatched\",\n }),\n );\n });\n"],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { n as ContextReference } from "./References-URDAtapt.mjs";
2
+ import { ContextError } from "./Errors.mjs";
3
+ import { t as BrowserbaseClient } from "./Client-Ca0zSg1n.mjs";
4
+ import { Context, Effect, Layer, Schema } from "effect";
5
+ declare namespace Contexts_d_exports {
6
+ export { BrowserbaseContexts, ContextCreation, ContextMetadata };
7
+ }
8
+ declare const ContextMetadata_base: Schema.Class<ContextMetadata, Schema.Struct<{
9
+ readonly reference: typeof ContextReference;
10
+ readonly createdAt: Schema.String;
11
+ readonly updatedAt: Schema.String;
12
+ readonly name: Schema.optionalKey<Schema.String>;
13
+ }>, {}>;
14
+ export declare class ContextMetadata extends ContextMetadata_base {}
15
+ declare const ContextCreation_base: Schema.Class<ContextCreation, Schema.Struct<{
16
+ readonly reference: typeof ContextReference;
17
+ }>, {}>;
18
+ export declare class ContextCreation extends ContextCreation_base {}
19
+ declare const BrowserbaseContexts_base: Context.ServiceClass<BrowserbaseContexts, "effect-browserbase/Contexts", {
20
+ readonly create: (options?: {
21
+ readonly name?: string;
22
+ }) => Effect.Effect<ContextCreation, ContextError>;
23
+ readonly retrieve: (reference: ContextReference) => Effect.Effect<ContextMetadata, ContextError>;
24
+ readonly delete: (reference: ContextReference) => Effect.Effect<void, ContextError>;
25
+ }>;
26
+ /** Context administration is independent of any live browser connection. */
27
+ export declare class BrowserbaseContexts extends BrowserbaseContexts_base {
28
+ static readonly layer: Layer.Layer<BrowserbaseContexts, never, BrowserbaseClient>;
29
+ }
30
+ //#endregion
31
+ export { Contexts_d_exports as t };
32
+ //# sourceMappingURL=Contexts.d.mts.map
@@ -0,0 +1,103 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
+ import { ContextReference, Identifier } from "./References.mjs";
3
+ import { ContextError } from "./Errors.mjs";
4
+ import { t as BrowserbaseClient } from "./Client-D1_xYM9o.mjs";
5
+ import { n as isContextWriterBusy } from "./ContextWriter-BrQmoXRg.mjs";
6
+ import { Context, Effect, Layer, Schema } from "effect";
7
+ //#region src/Contexts.ts
8
+ var Contexts_exports = /* @__PURE__ */ __exportAll({
9
+ BrowserbaseContexts: () => BrowserbaseContexts,
10
+ ContextCreation: () => ContextCreation,
11
+ ContextMetadata: () => ContextMetadata
12
+ });
13
+ const Timestamp = Schema.String.check(Schema.isMaxLength(64));
14
+ const ContextName = Schema.NonEmptyString.check(Schema.isMaxLength(1024), Schema.makeFilter((value) => value.trim().length > 0));
15
+ const ProviderContext = Schema.Struct({
16
+ id: Identifier,
17
+ projectId: Identifier,
18
+ createdAt: Timestamp,
19
+ updatedAt: Timestamp,
20
+ name: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(1024)))
21
+ });
22
+ var ContextMetadata = class extends Schema.Class("BrowserbaseContextMetadata")({
23
+ reference: ContextReference,
24
+ createdAt: Timestamp,
25
+ updatedAt: Timestamp,
26
+ name: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(1024)))
27
+ }) {};
28
+ var ContextCreation = class extends Schema.Class("BrowserbaseContextCreation")({ reference: ContextReference }) {};
29
+ const fromClient = (operation, error) => ContextError.make({
30
+ operation,
31
+ reason: error.reason,
32
+ ...error.outcome === void 0 ? {} : { outcome: error.outcome },
33
+ ...error.status === void 0 ? {} : { status: error.status },
34
+ ...error.retryAfterMillis === void 0 ? {} : { retryAfterMillis: error.retryAfterMillis }
35
+ });
36
+ const configuration = (operation) => ContextError.make({
37
+ operation,
38
+ reason: "configuration",
39
+ outcome: "undispatched"
40
+ });
41
+ const malformed = (operation, mutation = false) => ContextError.make({
42
+ operation,
43
+ reason: "malformed",
44
+ ...mutation ? { outcome: "unknown" } : {}
45
+ });
46
+ /** Context administration is independent of any live browser connection. */
47
+ var BrowserbaseContexts = class BrowserbaseContexts extends Context.Service()("effect-browserbase/Contexts") {
48
+ static layer = Layer.effect(BrowserbaseContexts, Effect.gen(function* () {
49
+ const client = yield* BrowserbaseClient;
50
+ const validate = Effect.fnUntraced(function* (reference, operation) {
51
+ const ref = yield* Schema.decodeEffect(ContextReference)(reference, { onExcessProperty: "error" }).pipe(Effect.mapError(() => configuration(operation)));
52
+ if (ref.projectId !== client.projectId) return yield* ContextError.make({
53
+ operation,
54
+ reason: "authorization",
55
+ outcome: "undispatched"
56
+ });
57
+ return ref;
58
+ });
59
+ const create = Effect.fn("BrowserbaseContexts.create")(function* (options = {}) {
60
+ const value = yield* Schema.decodeEffect(Schema.Struct({ name: Schema.optionalKey(ContextName) }))(options, { onExcessProperty: "error" }).pipe(Effect.mapError(() => configuration("context-create")));
61
+ const raw = yield* client.json("POST", "/v1/contexts", {
62
+ projectId: client.projectId,
63
+ ...value.name === void 0 ? {} : { name: value.name.trim() }
64
+ }).pipe(Effect.mapError((error) => fromClient("context-create", error)));
65
+ const created = yield* Schema.decodeUnknownEffect(Schema.Struct({ id: Identifier }))(raw).pipe(Effect.mapError(() => malformed("context-create", true)));
66
+ return ContextCreation.make({ reference: ContextReference.make({
67
+ provider: "browserbase",
68
+ projectId: client.projectId,
69
+ contextId: created.id
70
+ }) });
71
+ });
72
+ const retrieve = Effect.fn("BrowserbaseContexts.retrieve")(function* (reference) {
73
+ const ref = yield* validate(reference, "context-retrieve");
74
+ const raw = yield* client.json("GET", `/v1/contexts/${encodeURIComponent(ref.contextId)}`).pipe(Effect.mapError((error) => fromClient("context-retrieve", error)));
75
+ const value = yield* Schema.decodeUnknownEffect(ProviderContext)(raw).pipe(Effect.mapError(() => malformed("context-retrieve")));
76
+ if (value.id !== ref.contextId || value.projectId !== ref.projectId) return yield* malformed("context-retrieve");
77
+ return ContextMetadata.make({
78
+ reference: ref,
79
+ createdAt: value.createdAt,
80
+ updatedAt: value.updatedAt,
81
+ ...value.name === void 0 ? {} : { name: value.name }
82
+ });
83
+ });
84
+ const remove = Effect.fn("BrowserbaseContexts.delete")(function* (reference) {
85
+ const ref = yield* validate(reference, "context-delete");
86
+ if (isContextWriterBusy(ref)) return yield* ContextError.make({
87
+ operation: "context-delete",
88
+ reason: "active",
89
+ outcome: "undispatched"
90
+ });
91
+ yield* client.noContent("DELETE", `/v1/contexts/${encodeURIComponent(ref.contextId)}`).pipe(Effect.mapError((error) => fromClient("context-delete", error)));
92
+ });
93
+ return BrowserbaseContexts.of({
94
+ create,
95
+ retrieve,
96
+ delete: remove
97
+ });
98
+ }));
99
+ };
100
+ //#endregion
101
+ export { BrowserbaseContexts, ContextCreation, ContextMetadata, Contexts_exports as t };
102
+
103
+ //# sourceMappingURL=Contexts.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Contexts.mjs","names":[],"sources":["../src/Contexts.ts"],"sourcesContent":["import { Context, Effect, Layer, Schema } from \"effect\";\n\nimport { BrowserbaseClient } from \"./Client.ts\";\nimport type { ClientError } from \"./Errors.ts\";\nimport { ContextError } from \"./Errors.ts\";\nimport { isContextWriterBusy } from \"./internal/session/ContextWriter.ts\";\nimport { ContextReference, Identifier } from \"./References.ts\";\n\nconst Timestamp = Schema.String.check(Schema.isMaxLength(64));\n\nconst ContextName = Schema.NonEmptyString.check(\n Schema.isMaxLength(1024),\n Schema.makeFilter((value) => value.trim().length > 0),\n);\n\nconst ProviderContext = Schema.Struct({\n id: Identifier,\n projectId: Identifier,\n createdAt: Timestamp,\n updatedAt: Timestamp,\n name: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(1024))),\n});\n\nexport class ContextMetadata extends Schema.Class<ContextMetadata>(\"BrowserbaseContextMetadata\")({\n reference: ContextReference,\n createdAt: Timestamp,\n updatedAt: Timestamp,\n name: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(1024))),\n}) {}\n\nexport class ContextCreation extends Schema.Class<ContextCreation>(\"BrowserbaseContextCreation\")({\n reference: ContextReference,\n}) {}\n\nconst fromClient = (operation: ContextError[\"operation\"], error: ClientError): ContextError =>\n ContextError.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 configuration = (operation: ContextError[\"operation\"]) =>\n ContextError.make({ operation, reason: \"configuration\", outcome: \"undispatched\" });\n\nconst malformed = (operation: ContextError[\"operation\"], mutation = false) =>\n ContextError.make({\n operation,\n reason: \"malformed\",\n ...(mutation ? { outcome: \"unknown\" as const } : {}),\n });\n\n/** Context administration is independent of any live browser connection. */\nexport class BrowserbaseContexts extends Context.Service<\n BrowserbaseContexts,\n {\n readonly create: (options?: {\n readonly name?: string;\n }) => Effect.Effect<ContextCreation, ContextError>;\n readonly retrieve: (\n reference: ContextReference,\n ) => Effect.Effect<ContextMetadata, ContextError>;\n readonly delete: (reference: ContextReference) => Effect.Effect<void, ContextError>;\n }\n>()(\"effect-browserbase/Contexts\") {\n static readonly layer: Layer.Layer<BrowserbaseContexts, never, BrowserbaseClient> = Layer.effect(\n BrowserbaseContexts,\n Effect.gen(function* () {\n const client = yield* BrowserbaseClient;\n\n const validate = Effect.fnUntraced(function* (\n reference: ContextReference,\n operation: ContextError[\"operation\"],\n ) {\n const ref = yield* Schema.decodeEffect(ContextReference)(reference, {\n onExcessProperty: \"error\",\n }).pipe(Effect.mapError(() => configuration(operation)));\n\n if (ref.projectId !== client.projectId)\n return yield* ContextError.make({\n operation,\n reason: \"authorization\",\n outcome: \"undispatched\",\n });\n\n return ref;\n });\n\n const create = Effect.fn(\"BrowserbaseContexts.create\")(function* (\n options: { readonly name?: string } = {},\n ) {\n const value = yield* Schema.decodeEffect(\n Schema.Struct({ name: Schema.optionalKey(ContextName) }),\n )(options, { onExcessProperty: \"error\" }).pipe(\n Effect.mapError(() => configuration(\"context-create\")),\n );\n\n const raw = yield* client\n .json(\"POST\", \"/v1/contexts\", {\n projectId: client.projectId,\n ...(value.name === undefined ? {} : { name: value.name.trim() }),\n })\n .pipe(Effect.mapError((error) => fromClient(\"context-create\", error)));\n\n const created = yield* Schema.decodeUnknownEffect(Schema.Struct({ id: Identifier }))(\n raw,\n ).pipe(Effect.mapError(() => malformed(\"context-create\", true)));\n\n return ContextCreation.make({\n reference: ContextReference.make({\n provider: \"browserbase\",\n projectId: client.projectId,\n contextId: created.id,\n }),\n });\n });\n\n const retrieve = Effect.fn(\"BrowserbaseContexts.retrieve\")(function* (\n reference: ContextReference,\n ) {\n const ref = yield* validate(reference, \"context-retrieve\");\n\n const raw = yield* client\n .json(\"GET\", `/v1/contexts/${encodeURIComponent(ref.contextId)}`)\n .pipe(Effect.mapError((error) => fromClient(\"context-retrieve\", error)));\n\n const value = yield* Schema.decodeUnknownEffect(ProviderContext)(raw).pipe(\n Effect.mapError(() => malformed(\"context-retrieve\")),\n );\n\n if (value.id !== ref.contextId || value.projectId !== ref.projectId)\n return yield* malformed(\"context-retrieve\");\n\n return ContextMetadata.make({\n reference: ref,\n createdAt: value.createdAt,\n updatedAt: value.updatedAt,\n ...(value.name === undefined ? {} : { name: value.name }),\n });\n });\n\n const remove = Effect.fn(\"BrowserbaseContexts.delete\")(function* (\n reference: ContextReference,\n ) {\n const ref = yield* validate(reference, \"context-delete\");\n\n if (isContextWriterBusy(ref))\n return yield* ContextError.make({\n operation: \"context-delete\",\n reason: \"active\",\n outcome: \"undispatched\",\n });\n yield* client\n .noContent(\"DELETE\", `/v1/contexts/${encodeURIComponent(ref.contextId)}`)\n .pipe(Effect.mapError((error) => fromClient(\"context-delete\", error)));\n });\n\n return BrowserbaseContexts.of({ create, retrieve, delete: remove });\n }),\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { Clock, Duration, Effect } from "effect";
2
+ //#region src/internal/Deadline.ts
3
+ /** Monotonic elapsed time is distinct from provider dates and document presentation time. */
4
+ const nowMillis = Clock.monotonicTimeNanos.pipe(Effect.map((value) => Number(value) / 1e6));
5
+ const deadlineAfter = (millis) => nowMillis.pipe(Effect.map((now) => now + millis));
6
+ const until = (effect, deadline, timeout) => nowMillis.pipe(Effect.flatMap((now) => deadline <= now ? Effect.fail(timeout()) : effect.pipe(Effect.timeoutOrElse({
7
+ duration: Duration.millis(deadline - now),
8
+ orElse: () => Effect.fail(timeout())
9
+ }))));
10
+ //#endregion
11
+ export { nowMillis as n, until as r, deadlineAfter as t };
12
+
13
+ //# sourceMappingURL=Deadline-CrViaogr.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Deadline-CrViaogr.mjs","names":[],"sources":["../src/internal/Deadline.ts"],"sourcesContent":["import { Clock, Duration, Effect } from \"effect\";\n\n/** Monotonic elapsed time is distinct from provider dates and document presentation time. */\nexport const nowMillis = Clock.monotonicTimeNanos.pipe(\n Effect.map((value) => Number(value) / 1_000_000),\n);\n\nexport const deadlineAfter = (millis: number) => nowMillis.pipe(Effect.map((now) => now + millis));\n\nexport const until = <A, E, R, Timeout>(\n effect: Effect.Effect<A, E, R>,\n deadline: number,\n timeout: () => Timeout,\n): Effect.Effect<A, E | Timeout, R> =>\n nowMillis.pipe(\n Effect.flatMap((now) =>\n deadline <= now\n ? Effect.fail(timeout())\n : effect.pipe(\n Effect.timeoutOrElse({\n duration: Duration.millis(deadline - now),\n orElse: () => Effect.fail(timeout()),\n }),\n ),\n ),\n );\n"],"mappings":";;;AAGA,MAAa,YAAY,MAAM,mBAAmB,KAChD,OAAO,KAAK,UAAU,OAAO,KAAK,IAAI,GAAS,CACjD;AAEA,MAAa,iBAAiB,WAAmB,UAAU,KAAK,OAAO,KAAK,QAAQ,MAAM,MAAM,CAAC;AAEjG,MAAa,SACX,QACA,UACA,YAEA,UAAU,KACR,OAAO,SAAS,QACd,YAAY,MACR,OAAO,KAAK,QAAQ,CAAC,IACrB,OAAO,KACL,OAAO,cAAc;CACnB,UAAU,SAAS,OAAO,WAAW,GAAG;CACxC,cAAc,OAAO,KAAK,QAAQ,CAAC;AACrC,CAAC,CACH,CACN,CACF"}
@@ -0,0 +1,44 @@
1
+ import { o as SessionReference } from "./References-URDAtapt.mjs";
2
+ import { FileError } from "./Errors.mjs";
3
+ import { t as BrowserbaseClient } from "./Client-Ca0zSg1n.mjs";
4
+ import { t as BrowserbaseSessions } from "./Sessions-B8E4kMxo.mjs";
5
+ import { n as DownloadMetadata, t as ArtifactTransferPolicy } from "./Transfers-Czv5IZzJ.mjs";
6
+ import { Context, Effect, Layer, Schema, Stream } from "effect";
7
+ declare namespace Downloads_d_exports {
8
+ export { BrowserbaseDownloads, DownloadListing, DownloadPolicy, DownloadQuery };
9
+ }
10
+ export interface DownloadPolicy extends ArtifactTransferPolicy {
11
+ readonly mimeTypes: ReadonlyArray<string>;
12
+ }
13
+ export interface DownloadListing {
14
+ readonly downloads: ReadonlyArray<DownloadMetadata>;
15
+ readonly total: number;
16
+ readonly offset: number;
17
+ readonly complete: boolean;
18
+ }
19
+ /** Provider-side filters over one session's files; every bound is optional. */
20
+ export declare const DownloadQuery: Schema.Struct<{
21
+ readonly offset: Schema.optionalKey<Schema.Int>;
22
+ readonly filename: Schema.optionalKey<Schema.NonEmptyString>;
23
+ readonly mimeType: Schema.optionalKey<Schema.NonEmptyString>;
24
+ readonly minSize: Schema.optionalKey<Schema.Natural>;
25
+ readonly maxSize: Schema.optionalKey<Schema.Natural>;
26
+ readonly createdAfter: Schema.optionalKey<Schema.String>;
27
+ readonly createdBefore: Schema.optionalKey<Schema.String>;
28
+ }>;
29
+ export type DownloadQuery = typeof DownloadQuery.Type;
30
+ declare const BrowserbaseDownloads_base: Context.ServiceClass<BrowserbaseDownloads, "effect-browserbase/Downloads", {
31
+ readonly list: (reference: SessionReference, query?: DownloadQuery) => Effect.Effect<DownloadListing, FileError>;
32
+ readonly metadata: (reference: SessionReference, downloadId: string) => Effect.Effect<DownloadMetadata, FileError>;
33
+ readonly stream: (reference: SessionReference, downloadId: string, policy: DownloadPolicy) => Stream.Stream<Uint8Array, FileError>;
34
+ /** Deletes one stored file. A lost reply is `outcome: "unknown"` and is never retried. */
35
+ readonly delete: (reference: SessionReference, downloadId: string) => Effect.Effect<void, FileError>;
36
+ readonly waitForNew: (reference: SessionReference, previousIds: ReadonlyArray<string>, timeoutMillis?: number) => Effect.Effect<ReadonlyArray<DownloadMetadata>, FileError>;
37
+ }>;
38
+ /** Website files are not session-recording MP4s. They retain their own provider download ID. */
39
+ export declare class BrowserbaseDownloads extends BrowserbaseDownloads_base {
40
+ static readonly layer: Layer.Layer<BrowserbaseDownloads, never, BrowserbaseClient | BrowserbaseSessions>;
41
+ }
42
+ //#endregion
43
+ export { Downloads_d_exports as t };
44
+ //# sourceMappingURL=Downloads.d.mts.map
@@ -0,0 +1,142 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
+ import { Identifier } from "./References.mjs";
3
+ import { FileError } from "./Errors.mjs";
4
+ import { DownloadMetadata } from "./Transfers.mjs";
5
+ import { t as BrowserbaseClient } from "./Client-D1_xYM9o.mjs";
6
+ import { t as downloadTransferPolicy } from "./TransferPolicy-DQ06i7SZ.mjs";
7
+ import { n as nowMillis, r as until, t as deadlineAfter } from "./Deadline-CrViaogr.mjs";
8
+ import { t as BrowserbaseSessions } from "./Sessions-CtbseWEh.mjs";
9
+ import { Context, Effect, Layer, Schema, Stream } from "effect";
10
+ //#region src/Downloads.ts
11
+ var Downloads_exports = /* @__PURE__ */ __exportAll({
12
+ BrowserbaseDownloads: () => BrowserbaseDownloads,
13
+ DownloadQuery: () => DownloadQuery
14
+ });
15
+ const Timestamp = Schema.String.check(Schema.isMaxLength(64));
16
+ /** Provider-side filters over one session's files; every bound is optional. */
17
+ const DownloadQuery = Schema.Struct({
18
+ offset: Schema.optionalKey(Schema.Int.check(Schema.isBetween({
19
+ minimum: 0,
20
+ maximum: 1e4
21
+ }))),
22
+ filename: Schema.optionalKey(Schema.NonEmptyString.check(Schema.isMaxLength(1024))),
23
+ mimeType: Schema.optionalKey(Schema.NonEmptyString.check(Schema.isMaxLength(256))),
24
+ minSize: Schema.optionalKey(Schema.Natural),
25
+ maxSize: Schema.optionalKey(Schema.Natural),
26
+ createdAfter: Schema.optionalKey(Timestamp),
27
+ createdBefore: Schema.optionalKey(Timestamp)
28
+ });
29
+ const Listing = Schema.Struct({
30
+ downloads: Schema.Array(DownloadMetadata).check(Schema.isMaxLength(100)),
31
+ total: Schema.Natural
32
+ });
33
+ const failure = (operation, reason) => FileError.make({
34
+ operation,
35
+ reason
36
+ });
37
+ const fromClient = (operation) => (error) => FileError.make({
38
+ operation,
39
+ reason: error.reason,
40
+ ...error.outcome === void 0 ? {} : { outcome: error.outcome },
41
+ ...error.status === void 0 ? {} : { status: error.status },
42
+ ...error.retryAfterMillis === void 0 ? {} : { retryAfterMillis: error.retryAfterMillis }
43
+ });
44
+ const within = (effect, deadline, operation) => until(effect, deadline, () => failure(operation, "timeout"));
45
+ /** Website files are not session-recording MP4s. They retain their own provider download ID. */
46
+ var BrowserbaseDownloads = class BrowserbaseDownloads extends Context.Service()("effect-browserbase/Downloads") {
47
+ static layer = Layer.effect(BrowserbaseDownloads, Effect.gen(function* () {
48
+ const client = yield* BrowserbaseClient;
49
+ const sessions = yield* BrowserbaseSessions;
50
+ const owned = (ref, operation) => sessions.retrieve(ref).pipe(Effect.mapError((error) => FileError.make({
51
+ operation,
52
+ reason: error.reason
53
+ })), Effect.asVoid);
54
+ const list = Effect.fnUntraced(function* (ref, query = {}) {
55
+ const checked = yield* Schema.decodeEffect(DownloadQuery)(query, { onExcessProperty: "error" }).pipe(Effect.mapError(() => failure("downloads-list", "configuration")));
56
+ const offset = checked.offset ?? 0;
57
+ yield* owned(ref, "downloads-list");
58
+ const search = new URLSearchParams({
59
+ sessionId: ref.sessionId,
60
+ limit: "100",
61
+ offset: String(offset)
62
+ });
63
+ for (const key of [
64
+ "filename",
65
+ "mimeType",
66
+ "minSize",
67
+ "maxSize",
68
+ "createdAfter",
69
+ "createdBefore"
70
+ ]) {
71
+ const value = checked[key];
72
+ if (value !== void 0) search.set(key, String(value));
73
+ }
74
+ const raw = yield* client.json("GET", `/v1/downloads?${search}`).pipe(Effect.mapError(fromClient("downloads-list")), Effect.flatMap((value) => Schema.decodeUnknownEffect(Listing)(value).pipe(Effect.mapError(() => failure("downloads-list", "malformed")))));
75
+ if (raw.downloads.some((entry) => entry.sessionId !== ref.sessionId) || new Set(raw.downloads.map((entry) => entry.id)).size !== raw.downloads.length) return yield* failure("downloads-list", "malformed");
76
+ return {
77
+ ...raw,
78
+ offset,
79
+ complete: offset + raw.downloads.length >= raw.total
80
+ };
81
+ });
82
+ const metadata = Effect.fnUntraced(function* (ref, id) {
83
+ yield* Schema.decodeEffect(Identifier)(id).pipe(Effect.mapError(() => failure("download-metadata", "configuration")));
84
+ yield* owned(ref, "download-metadata");
85
+ const value = yield* client.json("GET", `/v1/downloads/${encodeURIComponent(id)}`).pipe(Effect.mapError(fromClient("download-metadata")), Effect.flatMap((raw) => Schema.decodeUnknownEffect(DownloadMetadata)(raw).pipe(Effect.mapError(() => failure("download-metadata", "malformed")))));
86
+ if (value.id !== id || value.sessionId !== ref.sessionId) return yield* failure("download-metadata", "malformed");
87
+ return value;
88
+ });
89
+ const stream = (ref, id, policy) => Stream.unwrap(Effect.gen(function* () {
90
+ const { maxBytes, timeoutMillis, mimeTypes } = yield* downloadTransferPolicy(policy, () => failure("download", "configuration"));
91
+ const deadline = yield* deadlineAfter(timeoutMillis);
92
+ const file = yield* within(metadata(ref, id), deadline, "download");
93
+ if (!mimeTypes.includes(file.mimeType.toLowerCase())) return yield* failure("download", "content-type");
94
+ if (file.size > maxBytes) return yield* failure("download", "limit");
95
+ let received = 0;
96
+ return client.bytes(`/v1/downloads/${encodeURIComponent(id)}`, maxBytes, ["application/octet-stream", file.mimeType.toLowerCase()], timeoutMillis, deadline).pipe(Stream.mapError(fromClient("download")), Stream.tap((chunk) => Effect.sync(() => {
97
+ received += chunk.byteLength;
98
+ })), Stream.concat(Stream.fromEffect(Effect.suspend(() => received === file.size ? Effect.void : Effect.fail(failure("download", "malformed")))).pipe(Stream.drain)));
99
+ }));
100
+ const waitForNew = Effect.fnUntraced(function* (ref, previousIds, timeoutMillis = 3e4) {
101
+ if (previousIds.length > 1e4 || !Number.isSafeInteger(timeoutMillis) || timeoutMillis < 1 || timeoutMillis > 3e5) return yield* failure("download-wait", "configuration");
102
+ const previous = new Set(previousIds);
103
+ const deadline = yield* deadlineAfter(timeoutMillis);
104
+ do {
105
+ const result = yield* within(list(ref), deadline, "download-wait");
106
+ if (!result.complete) return yield* failure("download-wait", "limit");
107
+ const fresh = result.downloads.filter((entry) => !previous.has(entry.id));
108
+ if (fresh.length > 0) return fresh;
109
+ const remaining = deadline - (yield* nowMillis);
110
+ if (remaining <= 0) break;
111
+ yield* Effect.sleep(Math.min(500, remaining));
112
+ } while ((yield* nowMillis) < deadline);
113
+ return yield* failure("download-wait", "timeout");
114
+ });
115
+ const remove = Effect.fnUntraced(function* (ref, id) {
116
+ yield* Schema.decodeEffect(Identifier)(id).pipe(Effect.mapError(() => FileError.make({
117
+ operation: "download-delete",
118
+ reason: "configuration",
119
+ outcome: "undispatched"
120
+ })));
121
+ yield* metadata(ref, id).pipe(Effect.mapError((error) => FileError.make({
122
+ operation: "download-delete",
123
+ reason: error.reason,
124
+ outcome: "undispatched",
125
+ ...error.status === void 0 ? {} : { status: error.status },
126
+ ...error.retryAfterMillis === void 0 ? {} : { retryAfterMillis: error.retryAfterMillis }
127
+ })));
128
+ yield* client.noContent("DELETE", `/v1/downloads/${encodeURIComponent(id)}`).pipe(Effect.mapError(fromClient("download-delete")));
129
+ });
130
+ return BrowserbaseDownloads.of({
131
+ list,
132
+ metadata,
133
+ stream,
134
+ waitForNew,
135
+ delete: remove
136
+ });
137
+ }));
138
+ };
139
+ //#endregion
140
+ export { BrowserbaseDownloads, DownloadQuery, Downloads_exports as t };
141
+
142
+ //# sourceMappingURL=Downloads.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Downloads.mjs","names":[],"sources":["../src/Downloads.ts"],"sourcesContent":["import { Context, Effect, Layer, Schema, Stream } from \"effect\";\n\nimport { BrowserbaseClient } from \"./Client.ts\";\nimport { type ClientError, FileError } from \"./Errors.ts\";\nimport { downloadTransferPolicy } 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 { type ArtifactTransferPolicy, DownloadMetadata } from \"./Transfers.ts\";\n\nexport interface DownloadPolicy extends ArtifactTransferPolicy {\n readonly mimeTypes: ReadonlyArray<string>;\n}\n\nexport interface DownloadListing {\n readonly downloads: ReadonlyArray<DownloadMetadata>;\n readonly total: number;\n readonly offset: number;\n readonly complete: boolean;\n}\n\nconst Timestamp = Schema.String.check(Schema.isMaxLength(64));\n\n/** Provider-side filters over one session's files; every bound is optional. */\nexport const DownloadQuery = Schema.Struct({\n offset: Schema.optionalKey(Schema.Int.check(Schema.isBetween({ minimum: 0, maximum: 10_000 }))),\n filename: Schema.optionalKey(Schema.NonEmptyString.check(Schema.isMaxLength(1024))),\n mimeType: Schema.optionalKey(Schema.NonEmptyString.check(Schema.isMaxLength(256))),\n minSize: Schema.optionalKey(Schema.Natural),\n maxSize: Schema.optionalKey(Schema.Natural),\n createdAfter: Schema.optionalKey(Timestamp),\n createdBefore: Schema.optionalKey(Timestamp),\n});\n\nexport type DownloadQuery = typeof DownloadQuery.Type;\n\nconst Listing = Schema.Struct({\n downloads: Schema.Array(DownloadMetadata).check(Schema.isMaxLength(100)),\n total: Schema.Natural,\n});\n\nconst failure = (operation: FileError[\"operation\"], reason: FileError[\"reason\"]) =>\n FileError.make({ operation, reason });\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\nconst within = <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n deadline: number,\n operation: FileError[\"operation\"],\n) => until(effect, deadline, () => failure(operation, \"timeout\"));\n\n/** Website files are not session-recording MP4s. They retain their own provider download ID. */\nexport class BrowserbaseDownloads extends Context.Service<\n BrowserbaseDownloads,\n {\n readonly list: (\n reference: SessionReference,\n query?: DownloadQuery,\n ) => Effect.Effect<DownloadListing, FileError>;\n readonly metadata: (\n reference: SessionReference,\n downloadId: string,\n ) => Effect.Effect<DownloadMetadata, FileError>;\n readonly stream: (\n reference: SessionReference,\n downloadId: string,\n policy: DownloadPolicy,\n ) => Stream.Stream<Uint8Array, FileError>;\n /** Deletes one stored file. A lost reply is `outcome: \"unknown\"` and is never retried. */\n readonly delete: (\n reference: SessionReference,\n downloadId: string,\n ) => Effect.Effect<void, FileError>;\n readonly waitForNew: (\n reference: SessionReference,\n previousIds: ReadonlyArray<string>,\n timeoutMillis?: number,\n ) => Effect.Effect<ReadonlyArray<DownloadMetadata>, FileError>;\n }\n>()(\"effect-browserbase/Downloads\") {\n static readonly layer: Layer.Layer<\n BrowserbaseDownloads,\n never,\n BrowserbaseClient | BrowserbaseSessions\n > = Layer.effect(\n BrowserbaseDownloads,\n Effect.gen(function* () {\n const client = yield* BrowserbaseClient;\n const sessions = yield* BrowserbaseSessions;\n\n // Files are readable while the session runs; only the exact owning session is admitted.\n const owned = (ref: SessionReference, operation: FileError[\"operation\"]) =>\n sessions.retrieve(ref).pipe(\n Effect.mapError((error) => FileError.make({ operation, reason: error.reason })),\n Effect.asVoid,\n );\n\n const list = Effect.fnUntraced(function* (ref: SessionReference, query: DownloadQuery = {}) {\n const checked = yield* Schema.decodeEffect(DownloadQuery)(query, {\n onExcessProperty: \"error\",\n }).pipe(Effect.mapError(() => failure(\"downloads-list\", \"configuration\")));\n\n const offset = checked.offset ?? 0;\n\n yield* owned(ref, \"downloads-list\");\n\n const search = new URLSearchParams({\n sessionId: ref.sessionId,\n limit: \"100\",\n offset: String(offset),\n });\n\n for (const key of [\n \"filename\",\n \"mimeType\",\n \"minSize\",\n \"maxSize\",\n \"createdAfter\",\n \"createdBefore\",\n ] as const) {\n const value = checked[key];\n\n if (value !== undefined) search.set(key, String(value));\n }\n\n const raw = yield* client.json(\"GET\", `/v1/downloads?${search}`).pipe(\n Effect.mapError(fromClient(\"downloads-list\")),\n Effect.flatMap((value) =>\n Schema.decodeUnknownEffect(Listing)(value).pipe(\n Effect.mapError(() => failure(\"downloads-list\", \"malformed\")),\n ),\n ),\n );\n\n if (\n raw.downloads.some((entry) => entry.sessionId !== ref.sessionId) ||\n new Set(raw.downloads.map((entry) => entry.id)).size !== raw.downloads.length\n ) {\n return yield* failure(\"downloads-list\", \"malformed\");\n }\n\n return { ...raw, offset, complete: offset + raw.downloads.length >= raw.total };\n });\n\n const metadata = Effect.fnUntraced(function* (ref: SessionReference, id: string) {\n yield* Schema.decodeEffect(Identifier)(id).pipe(\n Effect.mapError(() => failure(\"download-metadata\", \"configuration\")),\n );\n\n yield* owned(ref, \"download-metadata\");\n\n const value = yield* client.json(\"GET\", `/v1/downloads/${encodeURIComponent(id)}`).pipe(\n Effect.mapError(fromClient(\"download-metadata\")),\n Effect.flatMap((raw) =>\n Schema.decodeUnknownEffect(DownloadMetadata)(raw).pipe(\n Effect.mapError(() => failure(\"download-metadata\", \"malformed\")),\n ),\n ),\n );\n\n if (value.id !== id || value.sessionId !== ref.sessionId)\n return yield* failure(\"download-metadata\", \"malformed\");\n\n return value;\n });\n\n const stream = (ref: SessionReference, id: string, policy: DownloadPolicy) =>\n Stream.unwrap(\n Effect.gen(function* () {\n const { maxBytes, timeoutMillis, mimeTypes } = yield* downloadTransferPolicy(\n policy,\n () => failure(\"download\", \"configuration\"),\n );\n\n const deadline = yield* deadlineAfter(timeoutMillis);\n const file = yield* within(metadata(ref, id), deadline, \"download\");\n\n if (!mimeTypes.includes(file.mimeType.toLowerCase()))\n return yield* failure(\"download\", \"content-type\");\n if (file.size > maxBytes) return yield* failure(\"download\", \"limit\");\n let received = 0;\n\n return client\n .bytes(\n `/v1/downloads/${encodeURIComponent(id)}`,\n maxBytes,\n [\"application/octet-stream\", file.mimeType.toLowerCase()],\n timeoutMillis,\n deadline,\n )\n .pipe(\n Stream.mapError(fromClient(\"download\")),\n Stream.tap((chunk) =>\n Effect.sync(() => {\n received += chunk.byteLength;\n }),\n ),\n Stream.concat(\n Stream.fromEffect(\n Effect.suspend(() =>\n received === file.size\n ? Effect.void\n : Effect.fail(failure(\"download\", \"malformed\")),\n ),\n ).pipe(Stream.drain),\n ),\n );\n }),\n );\n\n const waitForNew = Effect.fnUntraced(function* (\n ref: SessionReference,\n previousIds: ReadonlyArray<string>,\n timeoutMillis = 30_000,\n ) {\n if (\n previousIds.length > 10_000 ||\n !Number.isSafeInteger(timeoutMillis) ||\n timeoutMillis < 1 ||\n timeoutMillis > 300_000\n ) {\n return yield* failure(\"download-wait\", \"configuration\");\n }\n const previous = new Set(previousIds);\n const deadline = yield* deadlineAfter(timeoutMillis);\n\n do {\n const result = yield* within(list(ref), deadline, \"download-wait\");\n\n // Never claim a complete candidate set from a partial listing.\n if (!result.complete) return yield* failure(\"download-wait\", \"limit\");\n const fresh = result.downloads.filter((entry) => !previous.has(entry.id));\n\n if (fresh.length > 0) return fresh;\n const remaining = deadline - (yield* nowMillis);\n\n if (remaining <= 0) break;\n yield* Effect.sleep(Math.min(500, remaining));\n } while ((yield* nowMillis) < deadline);\n\n return yield* failure(\"download-wait\", \"timeout\");\n });\n\n const remove = Effect.fnUntraced(function* (ref: SessionReference, id: string) {\n yield* Schema.decodeEffect(Identifier)(id).pipe(\n Effect.mapError(() =>\n FileError.make({\n operation: \"download-delete\",\n reason: \"configuration\",\n outcome: \"undispatched\",\n }),\n ),\n );\n\n // Ownership is proved by reading the file's session before any mutation.\n yield* metadata(ref, id).pipe(\n Effect.mapError((error) =>\n FileError.make({\n operation: \"download-delete\",\n reason: error.reason,\n outcome: \"undispatched\",\n ...(error.status === undefined ? {} : { status: error.status }),\n ...(error.retryAfterMillis === undefined\n ? {}\n : { retryAfterMillis: error.retryAfterMillis }),\n }),\n ),\n );\n\n yield* client\n .noContent(\"DELETE\", `/v1/downloads/${encodeURIComponent(id)}`)\n .pipe(Effect.mapError(fromClient(\"download-delete\")));\n });\n\n return BrowserbaseDownloads.of({ list, metadata, stream, waitForNew, delete: remove });\n }),\n );\n}\n"],"mappings":"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"}