frigatebird 0.2.0

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/CHANGELOG.md ADDED
@@ -0,0 +1,21 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0 - 2026-02-08
4
+
5
+ ### Added
6
+ - Modular architecture split across `cli`, `commands`, `client`, `browser`, and `lib` domains.
7
+ - Expanded bird-compatible CLI surface including timeline/search/news/lists/follows/likes/bookmarks/about/query commands.
8
+ - Integrated `x-list-manager` workflows: `refresh`, `add`, `remove`, and `batch`.
9
+ - Config and environment precedence matching bird semantics.
10
+ - Media attachment validation parity (`--media`, `--alt`, max counts, video constraints).
11
+ - Deterministic read-only end-to-end tests using local fixture pages and `--base-url`.
12
+ - Project skill files: `SKILL.md`, `SPEC.md`, `TASKS.md`.
13
+
14
+ ### Changed
15
+ - Runtime engine standardized on Playwright browser automation instead of GraphQL internals.
16
+ - `query-ids` retained as a compatibility command in Playwright mode.
17
+ - Documentation now explicitly describes Frigatebird intent and contrast with bird.
18
+
19
+ ### Tests
20
+ - Added broad unit coverage across option parsing, invocation normalization, handlers, and Playwright client behavior.
21
+ - Added read-only empty-account e2e coverage for command stability in low-data scenarios.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sean McLellan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,186 @@
1
+ # frigatebird
2
+
3
+ `frigatebird` is a Playwright-first X CLI that targets `bird` command parity and pulls in `x-list-manager` list automation.
4
+
5
+ It keeps the `bird` UX, but replaces deprecated/non-open GraphQL internals with browser automation against X web UI.
6
+
7
+ ## Intent
8
+
9
+ Frigatebird exists to keep the `bird` workflow alive after deprecation and closure:
10
+
11
+ - Preserve familiar command ergonomics from `bird`.
12
+ - Keep zero-API-key operation via local browser session cookies.
13
+ - Add first-class list management from `x-list-manager` (`add`, `remove`, `batch`, `refresh`).
14
+ - Provide one CLI for read workflows, account actions, and list operations.
15
+
16
+ ## Frigatebird vs Bird
17
+
18
+ | Area | `bird` | `frigatebird` |
19
+ |---|---|---|
20
+ | Primary engine | X internal GraphQL + query IDs | Playwright web automation |
21
+ | API keys | Not required | Not required |
22
+ | Auth | Browser cookies / env tokens | Browser cookies / env tokens |
23
+ | `query-ids` | Active GraphQL cache/refresh behavior | Compatibility command in Playwright mode |
24
+ | List manager commands | External project (`x-list-manager`) | Built in (`refresh`, `add`, `remove`, `batch`) |
25
+ | Selector/query fragility | Query ID churn | DOM selector churn |
26
+
27
+ ## Install
28
+
29
+ ```bash
30
+ npm install
31
+ npx playwright install chromium
32
+ ```
33
+
34
+ ## Usage
35
+
36
+ ```bash
37
+ # One-off
38
+ npx tsx src/cli.ts whoami
39
+
40
+ # Built binary
41
+ npm run build
42
+ node dist/cli.js --help
43
+ ```
44
+
45
+ ## Commands
46
+
47
+ ### bird-style parity commands
48
+
49
+ - `tweet <text>`
50
+ - `post <text>`
51
+ - `reply <tweet-id-or-url> <text>`
52
+ - `read <tweet-id-or-url> [--json] [--json-full]`
53
+ - `replies <tweet-id-or-url> [-n count] [--all] [--max-pages n] [--cursor str] [--delay ms] [--json] [--json-full]`
54
+ - `thread <tweet-id-or-url> [-n count] [--all] [--max-pages n] [--cursor str] [--delay ms] [--json] [--json-full]`
55
+ - `search <query> [-n count] [--all] [--max-pages n] [--cursor str] [--delay ms] [--json] [--json-full]`
56
+ - `mentions [-u @handle] [-n count] [--json] [--json-full]`
57
+ - `user-tweets <@handle> [-n count] [--all] [--max-pages n] [--cursor str] [--delay ms] [--json] [--json-full]`
58
+ - `home [-n count] [--following] [--all] [--max-pages n] [--delay ms] [--json] [--json-full]`
59
+ - `bookmarks [-n count] [--folder-id id] [--all] [--max-pages n] [--cursor str] [--expand-root-only] [--author-chain] [--author-only] [--full-chain-only] [--include-ancestor-branches] [--include-parent] [--thread-meta] [--sort-chronological] [--delay ms] [--json] [--json-full]`
60
+ - `unbookmark <tweet-id-or-url...> [--json]`
61
+ - `like <tweet-id-or-url>`
62
+ - `retweet <tweet-id-or-url>`
63
+ - `likes [-n count] [--all] [--max-pages n] [--cursor str] [--delay ms] [--json] [--json-full]`
64
+ - `follow <username-or-id>`
65
+ - `unfollow <username-or-id>`
66
+ - `following [--user userId] [-n count] [--all] [--max-pages n] [--cursor str] [--delay ms] [--json] [--json-full]`
67
+ - `followers [--user userId] [-n count] [--all] [--max-pages n] [--cursor str] [--delay ms] [--json] [--json-full]`
68
+ - `lists [--member-of] [-n count] [--json] [--json-full]`
69
+ - `list` (alias for `lists`)
70
+ - `list-timeline <list-id-or-url> [-n count] [--all] [--max-pages n] [--cursor str] [--delay ms] [--json] [--json-full]`
71
+ - `news [-n count] [--ai-only] [--with-tweets] [--tweets-per-item n] [--for-you] [--news-only] [--sports] [--entertainment] [--trending-only] [--json] [--json-full]`
72
+ - `trending` (alias for `news`)
73
+ - `about <@handle> [--json]`
74
+ - `query-ids [--fresh] [--json]` (compatibility mode in Playwright engine)
75
+ - `whoami [--json]`
76
+ - `check`
77
+ - `help [command]`
78
+
79
+ ### x-list-manager parity commands
80
+
81
+ - `refresh [--json]`
82
+ - `add <listName> <handles...> [--no-headless] [--json]`
83
+ - `remove <handle> <listName> [--no-headless] [--json]`
84
+ - `batch <file.json> [--no-headless] [--json]`
85
+
86
+ ## Global Options
87
+
88
+ - `--auth-token <token>`
89
+ - `--ct0 <token>`
90
+ - `--base-url <url>` (testing override, default `https://x.com`)
91
+ - `--cookie-source <chrome|firefox|safari|edge>` (repeatable)
92
+ - `--chrome-profile <name>`
93
+ - `--chrome-profile-dir <path>`
94
+ - `--firefox-profile <name>`
95
+ - `--cookie-timeout <ms>`
96
+ - `--timeout <ms>`
97
+ - `--quote-depth <n>`
98
+ - `--media <path>` (repeatable)
99
+ - `--alt <text>` (repeatable)
100
+ - `--plain`
101
+ - `--no-emoji`
102
+ - `--no-color`
103
+ - `--no-headless`
104
+
105
+ `tweet` and `reply` both consume `--media`/`--alt`.
106
+
107
+ Media constraints:
108
+ - up to 4 attachments
109
+ - only one video
110
+ - video cannot be mixed with other media
111
+ - supported extensions: `jpg`, `jpeg`, `png`, `webp`, `gif`, `mp4`, `m4v`, `mov`
112
+
113
+ ## Config + Env
114
+
115
+ Precedence: **CLI flags > env vars > project config > global config**.
116
+
117
+ Config files:
118
+ - Global (bird): `~/.config/bird/config.json5`
119
+ - Global (frigatebird): `~/.config/frigatebird/config.json5`
120
+ - Project (bird): `./.birdrc.json5`
121
+ - Project (frigatebird): `./.frigatebirdrc.json5`
122
+
123
+ Supported config keys:
124
+ - `authToken`, `ct0`, `baseUrl`
125
+ - `cookieSource`
126
+ - `chromeProfile`, `chromeProfileDir`, `firefoxProfile`
127
+ - `cookieTimeoutMs`, `timeoutMs`, `quoteDepth`
128
+
129
+ Supported env vars:
130
+ - Auth: `AUTH_TOKEN`, `CT0`, `TWITTER_AUTH_TOKEN`, `TWITTER_CT0`
131
+ - Cookie source: `BIRD_COOKIE_SOURCE`, `FRIGATEBIRD_COOKIE_SOURCE`
132
+ - Base URL: `BIRD_BASE_URL`, `FRIGATEBIRD_BASE_URL`
133
+ - Profiles: `BIRD_CHROME_PROFILE`, `BIRD_CHROME_PROFILE_DIR`, `BIRD_FIREFOX_PROFILE` (plus `FRIGATEBIRD_*` variants)
134
+ - Timeouts/depth: `BIRD_TIMEOUT_MS`, `BIRD_COOKIE_TIMEOUT_MS`, `BIRD_QUOTE_DEPTH` (plus `FRIGATEBIRD_*` variants)
135
+ - Output: `NO_COLOR`, `BIRD_PLAIN`, `FRIGATEBIRD_PLAIN`
136
+
137
+ ## Shorthand Invocation
138
+
139
+ If first argument is a tweet URL or ID, Frigatebird rewrites to `read`:
140
+
141
+ ```bash
142
+ npx tsx src/cli.ts 1891234567890123456 --json
143
+ ```
144
+
145
+ ## Architecture
146
+
147
+ - `src/cli/`: commander program assembly and global option wiring
148
+ - `src/commands/`: handler layer and output orchestration
149
+ - `src/client/`: `FrigatebirdClient` interface and Playwright implementation
150
+ - `src/browser/`: auth store, session lifecycle, scrape primitives
151
+ - `src/lib/`: identifiers, option parsing, invocation normalization, config, output
152
+
153
+ ## Skills Files
154
+
155
+ Frigatebird now includes skill-oriented project files (same ecosystem style used by `x-list-manager`):
156
+
157
+ - `SKILL.md`: AI-agent usage contract for this CLI
158
+ - `SPEC.md`: technical architecture and command behavior
159
+ - `TASKS.md`: parity/release checklist
160
+
161
+ ## Release Readiness
162
+
163
+ - `CHANGELOG.md` tracks release notes.
164
+ - `RELEASE.md` contains the release checklist and publish flow.
165
+ - GitHub workflows enforce CI + publish gates:
166
+ - `.github/workflows/ci.yml`
167
+ - `.github/workflows/release.yml`
168
+ - npm publish is triggered by GitHub Release `published` events using npm trusted publishing (OIDC, no npm token secret).
169
+ - `npm run release:check` runs lint + build + full tests + coverage.
170
+ - `npm run smoke:pack-install` validates clean install + binary entrypoint from a packed tarball.
171
+
172
+ ## Test
173
+
174
+ ```bash
175
+ npm run test:run
176
+ npm run test:coverage
177
+ npm run test:e2e
178
+ ```
179
+
180
+ `test:run` and `test:coverage` run unit/integration suites only.
181
+ `test:e2e` runs end-to-end read-only tests against empty-account fixtures.
182
+
183
+ ## Notes
184
+
185
+ - Frigatebird automates X web UI and depends on selectors that may change.
186
+ - Some deep `bird` GraphQL-only semantics are represented as compatibility flags in Playwright mode.
package/SKILL.md ADDED
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: frigatebird
3
+ description: Use Frigatebird to interact with X from the CLI with bird-compatible commands plus x-list-manager list automation. Use when users ask to read timelines/tweets, manage follows/lists, or automate list membership without X API keys.
4
+ argument-hint: 'whoami, read https://x.com/user/status/123, search "from:openai", add "AI News" @openai @anthropicai'
5
+ ---
6
+
7
+ # Frigatebird Skill
8
+
9
+ Frigatebird is a Playwright-first CLI that preserves `bird` command ergonomics and includes `x-list-manager` list operations.
10
+
11
+ ## Use This Skill When
12
+
13
+ - The user asks for `bird`-style CLI interactions on X.
14
+ - The user wants list automation (`add`, `remove`, `batch`, `refresh`).
15
+ - The user wants browser-cookie-based operation without API keys.
16
+
17
+ ## Core Workflow
18
+
19
+ 1. Verify auth/session health:
20
+ - `npx tsx src/cli.ts check`
21
+ - `npx tsx src/cli.ts whoami`
22
+ 2. For read-only tasks, prefer JSON output:
23
+ - `npx tsx src/cli.ts read <tweet-id-or-url> --json`
24
+ - `npx tsx src/cli.ts search "<query>" --json`
25
+ 3. For list-management tasks:
26
+ - `npx tsx src/cli.ts add "<List Name>" @handle1 @handle2`
27
+ - `npx tsx src/cli.ts remove @handle "<List Name>"`
28
+ - `npx tsx src/cli.ts batch accounts.json`
29
+ 4. Use pagination controls for large reads:
30
+ - `--all`, `--max-pages`, `--cursor`, `-n`
31
+
32
+ ## Command Groups
33
+
34
+ - Posting/mutations: `tweet`, `post`, `reply`, `like`, `retweet`, `follow`, `unfollow`, `unbookmark`
35
+ - Read/timelines: `read`, `replies`, `thread`, `search`, `mentions`, `user-tweets`, `home`, `bookmarks`, `likes`, `list-timeline`, `news`, `about`
36
+ - Identity/health: `check`, `whoami`, `query-ids`, `help`
37
+ - List automation: `refresh`, `add`, `remove`, `batch`, `lists`, `list`
38
+
39
+ ## Options That Matter Most
40
+
41
+ - Auth/cookies: `--auth-token`, `--ct0`, `--cookie-source`, `--chrome-profile`, `--firefox-profile`
42
+ - Determinism/testing: `--base-url`, `--plain`, `--no-color`
43
+ - Pagination: `-n`, `--all`, `--max-pages`, `--cursor`, `--delay`
44
+ - Output: `--json`, `--json-full`
45
+ - Media posting: `--media`, `--alt`
46
+
47
+ ## Caveats
48
+
49
+ - This tool depends on X web UI selectors; selector drift can break flows.
50
+ - `query-ids` is retained for command compatibility and does not drive Playwright execution.
51
+ - Some GraphQL-specific behavior from original `bird` is represented as compatibility flags in Playwright mode.
package/SPEC.md ADDED
@@ -0,0 +1,59 @@
1
+ # Frigatebird Technical Specification
2
+
3
+ ## Overview
4
+
5
+ Frigatebird is a TypeScript CLI for interacting with X via browser automation. It targets command-level parity with `bird` and includes list-management capabilities from `x-list-manager`.
6
+
7
+ ## Product Intent
8
+
9
+ - Preserve the user-facing `bird` command model after `bird` deprecation.
10
+ - Replace unstable/private GraphQL dependency with Playwright-driven web interactions.
11
+ - Consolidate read, mutation, and list-management operations into one CLI.
12
+
13
+ ## Architecture
14
+
15
+ ### 1. CLI Assembly (`src/cli/`, `src/cli.ts`)
16
+ - Declares the command surface with Commander.
17
+ - Normalizes shorthand invocation (`<tweet-id-or-url>` -> `read`).
18
+ - Resolves option precedence: CLI > env > project config > global config.
19
+
20
+ ### 2. Command Handlers (`src/commands/handlers.ts`)
21
+ - Maps CLI actions to client operations.
22
+ - Applies option parsing per command category.
23
+ - Normalizes JSON/plain output behavior.
24
+
25
+ ### 3. Client Layer (`src/client/`)
26
+ - `FrigatebirdClient` interface defines all command capabilities.
27
+ - `PlaywrightXClient` implements behavior through X web navigation and DOM scraping.
28
+
29
+ ### 4. Browser Layer (`src/browser/`)
30
+ - Session lifecycle and login checks.
31
+ - Cookie loading and auth store management.
32
+ - Scraping collectors for tweets, users, lists, and news.
33
+
34
+ ### 5. Shared Library (`src/lib/`)
35
+ - Identifier parsing (`tweet`, `list`, `profile` references).
36
+ - Option parsing and normalization.
37
+ - Output formatting and rendering.
38
+ - Config/env loading and merge precedence.
39
+
40
+ ## Compatibility Model
41
+
42
+ ### bird parity
43
+ - Frigatebird implements the `bird` CLI command/flag interface to maximize drop-in usability.
44
+ - GraphQL-only internals are represented as compatibility behavior where needed.
45
+
46
+ ### x-list-manager parity
47
+ - Frigatebird embeds list automation commands (`add`, `remove`, `batch`, `refresh`) with equivalent UX expectations.
48
+
49
+ ## Testing Strategy
50
+
51
+ - Unit tests cover parsing, invocation, handler orchestration, and client helper behavior.
52
+ - End-to-end tests run real browser flows against fixture pages for read-only scenarios and empty accounts.
53
+ - Release gate requires lint + build + full test + coverage.
54
+
55
+ ## Operational Constraints
56
+
57
+ - X DOM/selectors can change without notice.
58
+ - Auth depends on valid browser session cookies or explicit token input.
59
+ - Read-only fixture e2e validates resilient behavior under low/no timeline data.
package/TASKS.md ADDED
@@ -0,0 +1,29 @@
1
+ # Frigatebird Parity and Release Tasks
2
+
3
+ ## Parity
4
+ - [x] Match `bird` command surface from a CLI interface standpoint.
5
+ - [x] Keep shorthand tweet read invocation compatibility.
6
+ - [x] Implement pagination and JSON flags across read commands.
7
+ - [x] Support bird-style config/env precedence and key mappings.
8
+ - [x] Keep compatibility behavior for `query-ids` and bookmark expansion flags.
9
+
10
+ ## x-list-manager Integration
11
+ - [x] Include `refresh`, `add`, `remove`, and `batch` commands.
12
+ - [x] Preserve headless/headed toggle behavior with `--no-headless`.
13
+ - [x] Keep result reporting compatible for automation use.
14
+
15
+ ## Architecture
16
+ - [x] Split monolithic implementation into modular layers (`cli`, `commands`, `client`, `browser`, `lib`).
17
+ - [x] Define typed client interface for clear command contracts.
18
+ - [x] Centralize option parsing and output formatting.
19
+
20
+ ## Testing
21
+ - [x] Add/expand unit tests for CLI entry, invocation normalization, options, handlers, and client helpers.
22
+ - [x] Add read-only end-to-end coverage for empty-account conditions.
23
+ - [x] Ensure lint/build/test/coverage all pass before release.
24
+
25
+ ## Release Preparation
26
+ - [x] Add `CHANGELOG.md`.
27
+ - [x] Add `RELEASE.md` release checklist and publish flow.
28
+ - [x] Add `SKILL.md` + `SPEC.md` + `TASKS.md` for agent-oriented usage.
29
+ - [ ] Add mutation-focused e2e coverage against disposable test accounts (post-release hardening).
@@ -0,0 +1,145 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { getCookies } from "@steipete/sweet-cookie";
4
+ function normalizeDomain(domain) {
5
+ if (!domain)
6
+ return ".x.com";
7
+ return domain.startsWith(".") ? domain : `.${domain}`;
8
+ }
9
+ function toPlaywrightCookie(cookie) {
10
+ return {
11
+ name: cookie.name,
12
+ value: cookie.value,
13
+ domain: normalizeDomain(cookie.domain),
14
+ path: cookie.path ?? "/",
15
+ expires: cookie.expires ?? -1,
16
+ httpOnly: cookie.httpOnly ?? false,
17
+ secure: cookie.secure ?? true,
18
+ sameSite: cookie.sameSite ?? "Lax",
19
+ };
20
+ }
21
+ function mapSource(value) {
22
+ return value;
23
+ }
24
+ export class AuthStore {
25
+ authFile;
26
+ constructor(authFile = path.join(process.cwd(), "auth.json")) {
27
+ this.authFile = authFile;
28
+ }
29
+ loadFromDisk() {
30
+ if (!fs.existsSync(this.authFile))
31
+ return null;
32
+ try {
33
+ const parsed = JSON.parse(fs.readFileSync(this.authFile, "utf8"));
34
+ if (!Array.isArray(parsed.cookies) || parsed.cookies.length === 0)
35
+ return null;
36
+ return {
37
+ cookies: parsed.cookies,
38
+ source: parsed.source ?? "auth.json",
39
+ };
40
+ }
41
+ catch {
42
+ return null;
43
+ }
44
+ }
45
+ save(cookies, source) {
46
+ const payload = {
47
+ cookies,
48
+ source,
49
+ createdAt: new Date().toISOString(),
50
+ };
51
+ fs.writeFileSync(this.authFile, JSON.stringify(payload, null, 2));
52
+ }
53
+ clear() {
54
+ if (fs.existsSync(this.authFile)) {
55
+ fs.unlinkSync(this.authFile);
56
+ }
57
+ }
58
+ async extractFromBrowser(options) {
59
+ const browsers = options.cookieSource.map(mapSource);
60
+ const extraction = await getCookies({
61
+ url: "https://x.com",
62
+ browsers,
63
+ chromeProfile: options.chromeProfileDir ?? options.chromeProfile,
64
+ firefoxProfile: options.firefoxProfile,
65
+ timeoutMs: options.cookieTimeout,
66
+ }).catch(() => null);
67
+ if (!extraction || extraction.cookies.length === 0) {
68
+ return null;
69
+ }
70
+ const authToken = extraction.cookies.find((cookie) => cookie.name === "auth_token");
71
+ const ct0 = extraction.cookies.find((cookie) => cookie.name === "ct0");
72
+ if (!authToken || !ct0) {
73
+ return null;
74
+ }
75
+ const playwrightCookies = [
76
+ toPlaywrightCookie({
77
+ name: "auth_token",
78
+ value: authToken.value,
79
+ domain: authToken.domain,
80
+ path: authToken.path,
81
+ expires: authToken.expires,
82
+ httpOnly: true,
83
+ secure: authToken.secure,
84
+ sameSite: authToken.sameSite,
85
+ }),
86
+ toPlaywrightCookie({
87
+ name: "ct0",
88
+ value: ct0.value,
89
+ domain: ct0.domain,
90
+ path: ct0.path,
91
+ expires: ct0.expires,
92
+ httpOnly: ct0.httpOnly,
93
+ secure: ct0.secure,
94
+ sameSite: ct0.sameSite,
95
+ }),
96
+ ];
97
+ return {
98
+ cookies: playwrightCookies,
99
+ source: `browser:${options.cookieSource.join(",")}`,
100
+ };
101
+ }
102
+ fromManualTokens(options) {
103
+ if (!options.authToken || !options.ct0)
104
+ return null;
105
+ return {
106
+ source: "manual-flags",
107
+ cookies: [
108
+ toPlaywrightCookie({
109
+ name: "auth_token",
110
+ value: options.authToken,
111
+ domain: ".x.com",
112
+ path: "/",
113
+ httpOnly: true,
114
+ secure: true,
115
+ sameSite: "Lax",
116
+ }),
117
+ toPlaywrightCookie({
118
+ name: "ct0",
119
+ value: options.ct0,
120
+ domain: ".x.com",
121
+ path: "/",
122
+ httpOnly: false,
123
+ secure: true,
124
+ sameSite: "Lax",
125
+ }),
126
+ ],
127
+ };
128
+ }
129
+ async resolve(options, forceRefresh = false) {
130
+ const manual = this.fromManualTokens(options);
131
+ if (manual)
132
+ return manual;
133
+ if (!forceRefresh) {
134
+ const saved = this.loadFromDisk();
135
+ if (saved)
136
+ return saved;
137
+ }
138
+ const extracted = await this.extractFromBrowser(options);
139
+ if (extracted) {
140
+ this.save(extracted.cookies, extracted.source);
141
+ return extracted;
142
+ }
143
+ return null;
144
+ }
145
+ }