@solarisdk/browser 0.1.3 → 0.1.4

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.
@@ -5,8 +5,14 @@ export declare class BrowserSession {
5
5
  private readonly client;
6
6
  readonly session: Session;
7
7
  private readonly browser;
8
+ /** The session's primary context — seeded with the attached profile's
9
+ * storageState when there is one. See {@link context}. */
10
+ private readonly primaryContext?;
8
11
  private closed;
9
- constructor(client: Solari, session: Session, browser: Browser);
12
+ constructor(client: Solari, session: Session, browser: Browser,
13
+ /** The session's primary context — seeded with the attached profile's
14
+ * storageState when there is one. See {@link context}. */
15
+ primaryContext?: BrowserContext | undefined);
10
16
  /** Session id. */
11
17
  get id(): string;
12
18
  /** Plan-tier deadline (ISO 8601 UTC); session auto-releases at this point. */
@@ -23,11 +29,28 @@ export declare class BrowserSession {
23
29
  isConnected(): boolean;
24
30
  /** Browser version string (e.g. `"Chromium/130.0.6723.31"`). */
25
31
  version(): string;
26
- /** All open contexts. Sessions ship with a default context at `contexts()[0]`. */
32
+ /**
33
+ * The session's primary context — the one carrying the attached profile's
34
+ * cookies and localStorage. Use this (or {@link newPage}) rather than
35
+ * `contexts()[0]`, which is not guaranteed to be the seeded one.
36
+ */
37
+ get context(): BrowserContext | undefined;
38
+ /**
39
+ * All open contexts, straight from the browser.
40
+ *
41
+ * NOTE: this is NOT guaranteed to be non-empty, and `contexts()[0]` is NOT
42
+ * guaranteed to be the profile-seeded context — the pool only pre-creates an
43
+ * eager context when a proxy was requested. Prefer {@link context}.
44
+ */
27
45
  contexts(): BrowserContext[];
28
- /** Open a fresh browser context. Most callers want `contexts()[0]` instead. */
46
+ /** Open an ADDITIONAL, empty browser context. This does NOT carry the
47
+ * attached profile — use {@link context} for that. */
29
48
  newContext(options?: BrowserContextOptions): Promise<BrowserContext>;
30
- /** Open a fresh page in a new context. */
49
+ /**
50
+ * Open a page in the session's primary context, so an attached profile's
51
+ * cookies/localStorage are actually present. Falls back to a browser-level
52
+ * page only when there is no primary context.
53
+ */
31
54
  newPage(): Promise<Page>;
32
55
  /** Close the browser and release the session. Idempotent. */
33
56
  close(): Promise<void>;
@@ -2,11 +2,16 @@ export class BrowserSession {
2
2
  client;
3
3
  session;
4
4
  browser;
5
+ primaryContext;
5
6
  closed = false;
6
- constructor(client, session, browser) {
7
+ constructor(client, session, browser,
8
+ /** The session's primary context — seeded with the attached profile's
9
+ * storageState when there is one. See {@link context}. */
10
+ primaryContext) {
7
11
  this.client = client;
8
12
  this.session = session;
9
13
  this.browser = browser;
14
+ this.primaryContext = primaryContext;
10
15
  }
11
16
  /** Session id. */
12
17
  get id() {
@@ -40,16 +45,37 @@ export class BrowserSession {
40
45
  version() {
41
46
  return this.browser.version();
42
47
  }
43
- /** All open contexts. Sessions ship with a default context at `contexts()[0]`. */
48
+ /**
49
+ * The session's primary context — the one carrying the attached profile's
50
+ * cookies and localStorage. Use this (or {@link newPage}) rather than
51
+ * `contexts()[0]`, which is not guaranteed to be the seeded one.
52
+ */
53
+ get context() {
54
+ return this.primaryContext;
55
+ }
56
+ /**
57
+ * All open contexts, straight from the browser.
58
+ *
59
+ * NOTE: this is NOT guaranteed to be non-empty, and `contexts()[0]` is NOT
60
+ * guaranteed to be the profile-seeded context — the pool only pre-creates an
61
+ * eager context when a proxy was requested. Prefer {@link context}.
62
+ */
44
63
  contexts() {
45
64
  return this.browser.contexts();
46
65
  }
47
- /** Open a fresh browser context. Most callers want `contexts()[0]` instead. */
66
+ /** Open an ADDITIONAL, empty browser context. This does NOT carry the
67
+ * attached profile — use {@link context} for that. */
48
68
  async newContext(options) {
49
69
  return this.browser.newContext(options);
50
70
  }
51
- /** Open a fresh page in a new context. */
71
+ /**
72
+ * Open a page in the session's primary context, so an attached profile's
73
+ * cookies/localStorage are actually present. Falls back to a browser-level
74
+ * page only when there is no primary context.
75
+ */
52
76
  async newPage() {
77
+ if (this.primaryContext)
78
+ return this.primaryContext.newPage();
53
79
  return this.browser.newPage();
54
80
  }
55
81
  /** Close the browser and release the session. Idempotent. */
package/dist/index.d.ts CHANGED
@@ -103,11 +103,6 @@ export interface CreateSessionOptions {
103
103
  stealth?: boolean;
104
104
  /** Enable managed captcha solving. Requires `stealth: true`. */
105
105
  captcha?: boolean;
106
- /** Opt in to Cloudflare Web Bot Auth — sign every outbound HTTP
107
- * request with an Ed25519 key registered to our verified bot
108
- * directory. Independent of `stealth`. Silently inert if the
109
- * acquired slot has no signing key configured. */
110
- webBotAuth?: boolean;
111
106
  /** Request managed proxy egress. Requires `stealth: true`.
112
107
  *
113
108
  * proxy: "us"
package/dist/index.js CHANGED
@@ -2,6 +2,39 @@ import { chromium } from "patchright-core";
2
2
  import { LocalProxy } from "./local-proxy.js";
3
3
  import { BrowserSession } from "./browser-session.js";
4
4
  export { BrowserSession } from "./browser-session.js";
5
+ /**
6
+ * Narrow a {@link StorageState} to the shape `newContext({storageState})` wants.
7
+ *
8
+ * Our StorageState is deliberately permissive — every field optional, plus an
9
+ * index signature — because it doubles as the INPUT to `profiles.save()`, where
10
+ * callers hand-build partial objects. Playwright's parameter type requires the
11
+ * cookie fields to be present, so passing ours straight through is a TS2322 and
12
+ * callers were resorting to `as any`.
13
+ *
14
+ * Rather than tighten the public type (which would break anyone constructing a
15
+ * partial state to save), fill the defaults at this one seam. Values that are
16
+ * actually present always win; the defaults only cover fields the gateway
17
+ * omitted, and they match Playwright's own defaults for a host-only cookie.
18
+ */
19
+ function toPlaywrightStorageState(state) {
20
+ return {
21
+ cookies: (state.cookies ?? []).map((c) => ({
22
+ name: c.name,
23
+ value: c.value,
24
+ domain: c.domain ?? "",
25
+ path: c.path ?? "/",
26
+ // -1 is Playwright's "session cookie" sentinel.
27
+ expires: c.expires ?? -1,
28
+ httpOnly: c.httpOnly ?? false,
29
+ secure: c.secure ?? false,
30
+ sameSite: c.sameSite ?? "Lax",
31
+ })),
32
+ origins: (state.origins ?? []).map((o) => ({
33
+ origin: o.origin,
34
+ localStorage: o.localStorage ?? [],
35
+ })),
36
+ };
37
+ }
5
38
  export class SolariError extends Error {
6
39
  status;
7
40
  cause;
@@ -168,8 +201,6 @@ class SessionsResource {
168
201
  body.stealth = true;
169
202
  if (options?.captcha === true)
170
203
  body.captcha = true;
171
- if (options?.webBotAuth === true)
172
- body.webBotAuth = true;
173
204
  if (options?.proxy !== undefined)
174
205
  body.proxy = options.proxy;
175
206
  const res = await this.client.request("POST", "/sessions", Object.keys(body).length ? body : undefined);
@@ -322,7 +353,32 @@ export class Solari {
322
353
  if (probeEnabled) {
323
354
  await this._probeBrowserHealth(browser, probeTimeoutMs);
324
355
  }
325
- return new BrowserSession(this, session, browser);
356
+ // Materialise ONE primary context for the session.
357
+ //
358
+ // The gateway already fetches an attached profile's cookies +
359
+ // origins into session.storageState (and its own comment says it
360
+ // does so "so the SDK skips the newContext({storageState}) seed")
361
+ // — but the SDK never performed that seed, so every run wrote a
362
+ // new profile version and read none back. Seed it here.
363
+ //
364
+ // Also makes a context reliably available: the pool only
365
+ // pre-creates one when a proxy was requested, so on a plain
366
+ // launch() browser.contexts() was empty and contexts()[0]
367
+ // undefined — which the SDK's own docs pointed callers at.
368
+ const ctxOptions = {};
369
+ const tz = session.proxy?.timezoneId;
370
+ if (tz)
371
+ ctxOptions.timezoneId = tz;
372
+ if (session.storageState) {
373
+ ctxOptions.storageState = toPlaywrightStorageState(session.storageState);
374
+ }
375
+ const primary =
376
+ // Reuse the pool's eager context only when we have nothing
377
+ // to seed — storageState can only be applied at creation.
378
+ !ctxOptions.storageState && browser.contexts().length > 0
379
+ ? browser.contexts()[0]
380
+ : await browser.newContext(ctxOptions);
381
+ return new BrowserSession(this, session, browser, primary);
326
382
  }
327
383
  catch (err) {
328
384
  if (browser) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solarisdk/browser",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Official client SDK for Solari Browser.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",