facebook-comments-client 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.
- package/LICENSE +21 -0
- package/README.md +225 -0
- package/dist/cli.js +1608 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +1540 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +293 -0
- package/dist/index.d.ts +293 -0
- package/dist/index.js +1503 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 kenesuino
|
|
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,225 @@
|
|
|
1
|
+
# facebook-comments-client
|
|
2
|
+
|
|
3
|
+
Fetch comments from Facebook posts — including posts inside Facebook Groups where your account already has legitimate access — using an authorized Playwright session. Returns clean, normalized JSON that is independent of Facebook's internal response structure.
|
|
4
|
+
|
|
5
|
+
This is a **focused library**. It contains no database, no Supabase, no queues, no cron jobs, and no backend server. Its sole responsibility:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Facebook Post URL → Authenticate/Reuse Authorized Session → Fetch Available Comments → Return Clean Structured JSON
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install facebook-comments-client
|
|
15
|
+
# The library drives a real browser via Playwright:
|
|
16
|
+
npx playwright install chromium
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Requirements: Node.js 20+.
|
|
20
|
+
|
|
21
|
+
## Quick start
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { FacebookCommentsClient } from "facebook-comments-client";
|
|
25
|
+
|
|
26
|
+
const client = new FacebookCommentsClient({
|
|
27
|
+
session: {
|
|
28
|
+
type: "file",
|
|
29
|
+
path: "./facebook-session.json"
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const result = await client.getComments({
|
|
34
|
+
url: "https://www.facebook.com/groups/GROUP_ID/posts/POST_ID/",
|
|
35
|
+
maxComments: 100,
|
|
36
|
+
includeReplies: true
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
console.log(result.comments);
|
|
40
|
+
await client.close();
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Interactive login
|
|
44
|
+
|
|
45
|
+
The library never enters credentials for you. It opens a visible browser, you log in manually, and the authorized session is exported:
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import { FacebookCommentsClient } from "facebook-comments-client";
|
|
49
|
+
|
|
50
|
+
await FacebookCommentsClient.login({
|
|
51
|
+
outputPath: "./facebook-session.json"
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Or from the CLI:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npx fb-comments login --output ./facebook-session.json
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The helper waits for the Facebook `c_user` cookie to appear (up to 5 minutes by default), saves the Playwright storage state, and closes the browser.
|
|
62
|
+
|
|
63
|
+
## Session file usage
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
const client = new FacebookCommentsClient({
|
|
67
|
+
session: { type: "file", path: "./facebook-session.json" }
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`type: "storage"` is accepted as an alias. The file is a standard Playwright storage state (as produced by `context.storageState()` and by the login helper above).
|
|
72
|
+
|
|
73
|
+
## Environment variable usage
|
|
74
|
+
|
|
75
|
+
Handy for deployments. Encode a storage state once:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
const encoded = Buffer.from(JSON.stringify(storageState)).toString("base64");
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Then configure the client:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
const client = new FacebookCommentsClient({
|
|
85
|
+
session: { type: "env", envKey: "FACEBOOK_STORAGE_STATE" }
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The variable is base64(-url) decoded, JSON parsed, and validated with Zod before a browser context is created. You can also pass a plain cookie array via `{ type: "cookies", cookies }` or an inline object via `{ type: "state", state }`.
|
|
90
|
+
|
|
91
|
+
## Fetching comments
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
const result = await client.getComments({
|
|
95
|
+
url: "https://www.facebook.com/groups/123/posts/456/",
|
|
96
|
+
maxComments: 100, // default 50
|
|
97
|
+
includeReplies: true, // default false
|
|
98
|
+
maxReplies: 20, // default 20, per comment
|
|
99
|
+
timeout: 30000, // navigation timeout ms
|
|
100
|
+
headless: true // override client default
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Returns a normalized shape:
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
{
|
|
108
|
+
post: { id: "456", url: "https://www.facebook.com/groups/123/posts/456/" },
|
|
109
|
+
comments: [
|
|
110
|
+
{
|
|
111
|
+
id: "comment_123" | null,
|
|
112
|
+
author: { id: "user_123" | null, name: "John Doe" | null, profileUrl: "..." | null },
|
|
113
|
+
message: "Hello!",
|
|
114
|
+
createdAt: "2026-08-28T10:30:00.000Z" | null,
|
|
115
|
+
reactions: { total: 5 | null },
|
|
116
|
+
parentId: null,
|
|
117
|
+
replies: [ /* same shape */ ]
|
|
118
|
+
}
|
|
119
|
+
],
|
|
120
|
+
pagination: { hasMore: false, nextCursor: null }
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Every field degrades to `null` instead of crashing when Facebook's markup differs — missing profile URLs, unparseable timestamps, unavailable reaction counts, etc.
|
|
125
|
+
|
|
126
|
+
## Fetching replies
|
|
127
|
+
|
|
128
|
+
Set `includeReplies: true` (and optionally `maxReplies`). The fetcher expands "View more replies" controls (bounded) and nests replies under their parent comment with `parentId` set.
|
|
129
|
+
|
|
130
|
+
## Pagination
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
const page1 = await client.getComments({ url, maxComments: 25 });
|
|
134
|
+
|
|
135
|
+
if (page1.pagination.hasMore) {
|
|
136
|
+
const page2 = await client.getComments({
|
|
137
|
+
url,
|
|
138
|
+
maxComments: 25,
|
|
139
|
+
cursor: page1.pagination.nextCursor
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The cursor is an opaque base64url token — an offset into the comment stream. No Facebook internals leak into your code.
|
|
145
|
+
|
|
146
|
+
## Error handling
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
import {
|
|
150
|
+
FacebookClientError,
|
|
151
|
+
FacebookAuthenticationError,
|
|
152
|
+
FacebookSessionExpiredError,
|
|
153
|
+
FacebookPostNotFoundError,
|
|
154
|
+
FacebookAccessDeniedError,
|
|
155
|
+
FacebookExtractionError
|
|
156
|
+
} from "facebook-comments-client";
|
|
157
|
+
|
|
158
|
+
try {
|
|
159
|
+
const { comments } = await client.getComments({ url: postUrl });
|
|
160
|
+
} catch (error) {
|
|
161
|
+
if (error instanceof FacebookSessionExpiredError) {
|
|
162
|
+
console.log("Facebook session needs to be refreshed.");
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Every error carries a stable `code` (`FB_AUTH`, `FB_SESSION_EXPIRED`, `FB_POST_NOT_FOUND`, `FB_ACCESS_DENIED`, `FB_EXTRACTION`, `FB_CLIENT`), a safe human-readable message, and a `retryable` boolean. Error messages never contain cookies or storage-state content. See [docs/errors.md](docs/errors.md).
|
|
168
|
+
|
|
169
|
+
## Security notes
|
|
170
|
+
|
|
171
|
+
- **Treat session files as passwords.** A storage state grants full access to the logged-in account.
|
|
172
|
+
- The library never logs cookie values, tokens, or storage states; its logger redacts sensitive keys, and error messages are scrubbed.
|
|
173
|
+
- `facebook-session.json`, `*.storage-state.json`, and `.env` are in `.gitignore` — never commit them.
|
|
174
|
+
- Environment variables are convenient for deployment, but session expiration and secret handling are your responsibility. Prefer your platform's secret manager over plaintext `.env` files.
|
|
175
|
+
- Use sessions belonging to accounts that legitimately have access to the requested content. This library does not bypass logins, CAPTCHAs, or access controls, and contains no stealth, fingerprint-spoofing, proxy-rotation, or restriction-evasion features.
|
|
176
|
+
|
|
177
|
+
## Session refresh instructions
|
|
178
|
+
|
|
179
|
+
Facebook sessions expire (typically days to weeks):
|
|
180
|
+
|
|
181
|
+
1. `client.validateSession()` returns `{ valid: true, authenticated: false }`, or `getComments` throws `FacebookSessionExpiredError`.
|
|
182
|
+
2. Re-run the login helper: `await FacebookCommentsClient.login({ outputPath })` (or `fb-comments login`).
|
|
183
|
+
3. If you use the env-var provider, re-encode the fresh state and update the variable.
|
|
184
|
+
|
|
185
|
+
## Known limitations
|
|
186
|
+
|
|
187
|
+
- **Facebook markup is unstable by nature.** All selectors and text patterns live in [`src/config/selectors.ts`](src/config/selectors.ts); when extraction quality degrades, that one file is the place to look. Extraction issues throw `FacebookExtractionError` rather than returning garbage silently.
|
|
188
|
+
- The structured-data extractor is opportunistic; on most modern pages the accessibility-based DOM extractor does the real work.
|
|
189
|
+
- Timestamps shown as relative times ("2h") are approximations computed from fetch time.
|
|
190
|
+
- Comment ids are frequently absent in the DOM and are returned as `null`.
|
|
191
|
+
- Localization: text patterns currently target English UI text. Non-English Facebook UIs may need additional patterns in `selectors.ts`.
|
|
192
|
+
- Very long threads (hundreds of comments) require pagination; the load-more loop is intentionally bounded.
|
|
193
|
+
- Integration tests against live Facebook are opt-in (`tests/integration/live.test.ts`) and need `FB_TEST_URL` + `FACEBOOK_STORAGE_STATE`.
|
|
194
|
+
|
|
195
|
+
## CLI
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
# Login (manual, headed browser)
|
|
199
|
+
fb-comments login --output ./facebook-session.json
|
|
200
|
+
|
|
201
|
+
# Fetch comments
|
|
202
|
+
fb-comments comments "https://www.facebook.com/groups/123/posts/456/" --replies --limit 100
|
|
203
|
+
|
|
204
|
+
# Machine-readable output
|
|
205
|
+
fb-comments comments POST_URL --json
|
|
206
|
+
|
|
207
|
+
# Session from env var
|
|
208
|
+
FACEBOOK_STORAGE_STATE="..." fb-comments comments POST_URL
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Development
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
npm install
|
|
215
|
+
npx playwright install chromium
|
|
216
|
+
npm test # unit + fixture tests (offline, no Facebook login needed)
|
|
217
|
+
npm run build # dist/ ESM + CJS + types + CLI
|
|
218
|
+
npm run lint
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
See [docs/api.md](docs/api.md) for the full API surface, [docs/authentication.md](docs/authentication.md) and [docs/session-management.md](docs/session-management.md) for session details.
|
|
222
|
+
|
|
223
|
+
## License
|
|
224
|
+
|
|
225
|
+
MIT
|