@tabsircg/fb-sdk 1.2.1 → 2.0.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.
Files changed (144) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +410 -53
  3. package/dist/client.d.ts +19 -10
  4. package/dist/client.d.ts.map +1 -1
  5. package/dist/client.js +4 -2
  6. package/dist/client.js.map +1 -1
  7. package/dist/errors.d.ts +4 -0
  8. package/dist/errors.d.ts.map +1 -0
  9. package/dist/errors.js +2 -0
  10. package/dist/errors.js.map +1 -0
  11. package/dist/httpClient.d.ts +14 -4
  12. package/dist/httpClient.d.ts.map +1 -1
  13. package/dist/httpClient.js +112 -31
  14. package/dist/httpClient.js.map +1 -1
  15. package/dist/instagramClient.d.ts +174 -0
  16. package/dist/instagramClient.d.ts.map +1 -0
  17. package/dist/instagramClient.js +19 -0
  18. package/dist/instagramClient.js.map +1 -0
  19. package/dist/internal/batchable.d.ts +3 -2
  20. package/dist/internal/batchable.d.ts.map +1 -1
  21. package/dist/internal/batchable.js +17 -4
  22. package/dist/internal/batchable.js.map +1 -1
  23. package/dist/internal/error.d.ts +94 -1
  24. package/dist/internal/error.d.ts.map +1 -1
  25. package/dist/internal/error.js +219 -0
  26. package/dist/internal/error.js.map +1 -1
  27. package/dist/internal/fetchers.d.ts +2 -2
  28. package/dist/internal/fetchers.d.ts.map +1 -1
  29. package/dist/internal/fetchers.js +3 -0
  30. package/dist/internal/fetchers.js.map +1 -1
  31. package/dist/internal/poller.d.ts +8 -2
  32. package/dist/internal/poller.d.ts.map +1 -1
  33. package/dist/internal/poller.js +18 -0
  34. package/dist/internal/poller.js.map +1 -1
  35. package/dist/internal/utils.d.ts.map +1 -1
  36. package/dist/internal/utils.js.map +1 -1
  37. package/dist/lib/transformCase.d.ts.map +1 -1
  38. package/dist/lib/transformCase.js +5 -6
  39. package/dist/lib/transformCase.js.map +1 -1
  40. package/dist/resources/InsightResource.d.ts +2 -2
  41. package/dist/resources/InsightResource.d.ts.map +1 -1
  42. package/dist/resources/InsightResource.js +12 -8
  43. package/dist/resources/InsightResource.js.map +1 -1
  44. package/dist/resources/PageResource.d.ts +6 -6
  45. package/dist/resources/PageResource.d.ts.map +1 -1
  46. package/dist/resources/PageResource.js +11 -6
  47. package/dist/resources/PageResource.js.map +1 -1
  48. package/dist/resources/PostResource.d.ts +3 -3
  49. package/dist/resources/PostResource.d.ts.map +1 -1
  50. package/dist/resources/PostResource.js +5 -2
  51. package/dist/resources/PostResource.js.map +1 -1
  52. package/dist/resources/UserResource.d.ts +4 -4
  53. package/dist/resources/UserResource.d.ts.map +1 -1
  54. package/dist/resources/UserResource.js +4 -0
  55. package/dist/resources/UserResource.js.map +1 -1
  56. package/dist/resources/comment/CommentResource.d.ts +5 -8
  57. package/dist/resources/comment/CommentResource.d.ts.map +1 -1
  58. package/dist/resources/comment/CommentResource.js +5 -2
  59. package/dist/resources/comment/CommentResource.js.map +1 -1
  60. package/dist/resources/comment/PageCommentResource.d.ts +14 -0
  61. package/dist/resources/comment/PageCommentResource.d.ts.map +1 -0
  62. package/dist/resources/comment/PageCommentResource.js +73 -0
  63. package/dist/resources/comment/PageCommentResource.js.map +1 -0
  64. package/dist/resources/createBatchResource.d.ts +5 -1
  65. package/dist/resources/createBatchResource.d.ts.map +1 -1
  66. package/dist/resources/createBatchResource.js +30 -5
  67. package/dist/resources/createBatchResource.js.map +1 -1
  68. package/dist/resources/instagram/InstagramCommentResource.d.ts +20 -0
  69. package/dist/resources/instagram/InstagramCommentResource.d.ts.map +1 -0
  70. package/dist/resources/instagram/InstagramCommentResource.js +22 -0
  71. package/dist/resources/instagram/InstagramCommentResource.js.map +1 -0
  72. package/dist/resources/instagram/InstagramInsightResource.d.ts +136 -0
  73. package/dist/resources/instagram/InstagramInsightResource.d.ts.map +1 -0
  74. package/dist/resources/instagram/InstagramInsightResource.js +48 -0
  75. package/dist/resources/instagram/InstagramInsightResource.js.map +1 -0
  76. package/dist/resources/instagram/InstagramMediaNodeResource.d.ts +89 -0
  77. package/dist/resources/instagram/InstagramMediaNodeResource.d.ts.map +1 -0
  78. package/dist/resources/instagram/InstagramMediaNodeResource.js +18 -0
  79. package/dist/resources/instagram/InstagramMediaNodeResource.js.map +1 -0
  80. package/dist/resources/instagram/InstagramMediaResource.d.ts +18 -0
  81. package/dist/resources/instagram/InstagramMediaResource.d.ts.map +1 -0
  82. package/dist/resources/instagram/InstagramMediaResource.js +69 -0
  83. package/dist/resources/instagram/InstagramMediaResource.js.map +1 -0
  84. package/dist/resources/instagram/InstagramMentionsResource.d.ts +10 -0
  85. package/dist/resources/instagram/InstagramMentionsResource.d.ts.map +1 -0
  86. package/dist/resources/instagram/InstagramMentionsResource.js +19 -0
  87. package/dist/resources/instagram/InstagramMentionsResource.js.map +1 -0
  88. package/dist/resources/instagram/InstagramResource.d.ts +82 -0
  89. package/dist/resources/instagram/InstagramResource.d.ts.map +1 -0
  90. package/dist/resources/instagram/InstagramResource.js +26 -0
  91. package/dist/resources/instagram/InstagramResource.js.map +1 -0
  92. package/dist/store/memory.d.ts +1 -1
  93. package/dist/store/memory.d.ts.map +1 -1
  94. package/dist/store/memory.js +1 -0
  95. package/dist/store/memory.js.map +1 -1
  96. package/dist/store/redis.d.ts +1 -1
  97. package/dist/store/redis.d.ts.map +1 -1
  98. package/dist/store/redis.js +1 -1
  99. package/dist/store/redis.js.map +1 -1
  100. package/dist/store/types.d.ts.map +1 -1
  101. package/dist/types/facebookerror.d.ts +37 -0
  102. package/dist/types/facebookerror.d.ts.map +1 -0
  103. package/dist/types/facebookerror.js +2 -0
  104. package/dist/types/facebookerror.js.map +1 -0
  105. package/dist/types/facebookinsights.d.ts +2 -2
  106. package/dist/types/facebookinsights.d.ts.map +1 -1
  107. package/dist/types/facebookmedia.d.ts +1 -1
  108. package/dist/types/facebookmedia.d.ts.map +1 -1
  109. package/dist/types/facebookmedia.js +1 -1
  110. package/dist/types/facebookmedia.js.map +1 -1
  111. package/dist/types/facebookpage.d.ts +1 -1
  112. package/dist/types/facebookpage.d.ts.map +1 -1
  113. package/dist/types/facebookpage.js +1 -1
  114. package/dist/types/facebookpage.js.map +1 -1
  115. package/dist/types/facebookpost.d.ts +1 -1
  116. package/dist/types/facebookpost.d.ts.map +1 -1
  117. package/dist/types/facebookpost.js +1 -1
  118. package/dist/types/facebookpost.js.map +1 -1
  119. package/dist/types/facebookuser.d.ts +1 -1
  120. package/dist/types/facebookuser.d.ts.map +1 -1
  121. package/dist/types/facebookuser.js +1 -1
  122. package/dist/types/facebookuser.js.map +1 -1
  123. package/dist/types/instagram.d.ts +146 -0
  124. package/dist/types/instagram.d.ts.map +1 -0
  125. package/dist/types/instagram.js +3 -0
  126. package/dist/types/instagram.js.map +1 -0
  127. package/dist/types/instagraminsights.d.ts +114 -0
  128. package/dist/types/instagraminsights.d.ts.map +1 -0
  129. package/dist/types/instagraminsights.js +2 -0
  130. package/dist/types/instagraminsights.js.map +1 -0
  131. package/dist/types/shared.d.ts +2 -1
  132. package/dist/types/shared.d.ts.map +1 -1
  133. package/dist/types/shared.js.map +1 -1
  134. package/dist/types/webhook.d.ts +119 -35
  135. package/dist/types/webhook.d.ts.map +1 -1
  136. package/dist/webhook/handler.d.ts +4 -2
  137. package/dist/webhook/handler.d.ts.map +1 -1
  138. package/dist/webhook/handler.js +30 -19
  139. package/dist/webhook/handler.js.map +1 -1
  140. package/dist/webhook/normalize.d.ts +3 -0
  141. package/dist/webhook/normalize.d.ts.map +1 -0
  142. package/dist/webhook/normalize.js +191 -0
  143. package/dist/webhook/normalize.js.map +1 -0
  144. package/package.json +39 -8
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tabsir Ahammed
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 CHANGED
@@ -1,76 +1,433 @@
1
1
  # @tabsircg/fb-sdk
2
2
 
3
- A strongly-typed, modern TypeScript SDK for the Facebook Graph API (v25.0). It provides a fluent, resource-based interface with automatic `camelCase` ↔ `snake_case` transformation, seamless request batching, and an advanced type-safe field selector system that mimics GraphQL.
3
+ A small, strongly-typed Facebook Graph API SDK for Node.js.
4
4
 
5
- ## Tech Stack
6
- - **TypeScript** (v5.9.3) - Core language and advanced type system
7
- - **Axios** (v1.13.6) - HTTP client for interacting with the Graph API
8
- - **form-data** (v4.0.5) - For handling multipart/form-data (used in batching and media uploads)
9
- - **dotenv** (v17.3.1) - Environment variable management
10
- - **tsx** (v4.21.0) - For rapid development and execution of TypeScript files
5
+ It started as the Facebook layer for a scheduling tool (Scheduly) and was extracted as a standalone package. The goal is a thin, predictable wrapper around the Graph API — not a kitchen-sink client. **It currently covers a focused subset of the Graph API.** More surface area will land over time; see [Coverage](#coverage).
11
6
 
12
- ## Environment Variables
7
+ > Status: early. The published version is `1.2.x`. The public shape (resource factories, `BatchableRequest`, field selectors) is stable enough to use, but minor versions may still tighten types.
13
8
 
14
- No required environment variables are hardcoded into the SDK itself. However, to interact with the Facebook Graph API, you must supply a valid Access Token when initializing the client wrapper.
9
+ ---
15
10
 
16
- For development (`npm run dev`), you likely need to configure your `.env` file with a token to test against `src/temp/test.ts` (though `dotenv` usage is up to the consumer).
11
+ ## Highlights
17
12
 
18
- ## Scripts
13
+ - **Declarative field selection, fully typed.** The shape you await is exactly the shape you asked for — no `any`, no over-fetching, no manual type narrowing.
14
+ - **One primitive: `BatchableRequest<T>`.** Every Graph call returns a thenable that doubles as a batch sub-request. The same value can be `await`-ed directly or passed into `sdk.batch([...])`.
15
+ - **Automatic camelCase ↔ snake_case** at both runtime and type level. You write `createdTime`, the API sees `created_time`, you await `createdTime` again.
16
+ - **Native batch API** with automatic chunking past Facebook's 50-request limit.
17
+ - **First-class webhooks.** Facebook + Instagram webhooks normalized into one typed `onEvent` stream, plus an in-memory and a Redis store for store-accelerated comment fan-out.
18
+ - **Async upload helpers** for videos, reels, and images — including the 3-phase reel upload session, status polling, and 504 recovery.
19
+ - **Typed error hook.** An optional `onError` reports a strictly-typed `FacebookError` — a discriminated union you narrow on `.category`, with a `raw` escape hatch — for every failed request and batch sub-response. Observational: it never changes what's thrown or returned.
19
20
 
20
- | Command | Description |
21
- | :--- | :--- |
22
- | `npm run build` | Compiles the TypeScript source code to JavaScript ES2022 format inside the `dist/` directory. |
23
- | `npm run dev` | Runs the scratchpad/test file located at `src/temp/test.ts` using `tsx`. Useful for local testing. |
24
- | `npm run prepublishOnly` | Automatically runs `npm run build` prior to publishing the package to npm. |
21
+ ---
25
22
 
26
- ## Quick Start
23
+ ## Install
27
24
 
28
- ```typescript
29
- import { createFbSdk } from '@tabsircg/fb-sdk';
25
+ ```bash
26
+ npm install @tabsircg/fb-sdk
27
+ # or
28
+ pnpm add @tabsircg/fb-sdk
29
+ ```
30
+
31
+ Node 18+ recommended (the package is ESM and ships native ESM output).
32
+
33
+ The SDK pins **Graph API v25.0**.
34
+
35
+ ---
36
+
37
+ ## Quick start
38
+
39
+ ```ts
40
+ import { createFbSdk } from "@tabsircg/fb-sdk";
41
+
42
+ const sdk = createFbSdk()(process.env.FB_ACCESS_TOKEN!);
43
+
44
+ // Fetch the current user (the token's owner)
45
+ const me = await sdk.me.get({ id: true, name: true, picture: true });
46
+ // ^? { id: string; name: string; picture: { data: PictureData } }
47
+
48
+ // List the pages the user manages
49
+ const pages = await sdk.me.accounts({
50
+ fields: { id: true, name: true, accessToken: true },
51
+ });
52
+
53
+ // Fetch a single post with nested comments and reactions
54
+ const post = await sdk.post("123_456").get({
55
+ id: true,
56
+ message: true,
57
+ reactions: { summary: true },
58
+ comments: {
59
+ fields: { id: true, message: true, from: { id: true, name: true } },
60
+ options: { limit: 25 },
61
+ },
62
+ });
63
+
64
+ // Update a comment
65
+ await sdk.comment("789").update({ message: "edited" });
66
+ ```
67
+
68
+ Every call above is a `BatchableRequest<T>`. Each can be `await`-ed directly, *or* you can drop them into a batch:
69
+
70
+ ```ts
71
+ const [postRes, commentsRes] = await sdk.batch([
72
+ sdk.post("123_456").get({ id: true, message: true }),
73
+ sdk.page("me").comments.list({ fields: { id: true, message: true } }),
74
+ ]);
75
+
76
+ if (postRes.status === 200) {
77
+ console.log(postRes.data.message);
78
+ }
79
+ ```
80
+
81
+ ---
82
+
83
+ ## Coverage
84
+
85
+ What ships today:
86
+
87
+ | Area | Resource | Operations |
88
+ | --------- | ------------------------------------------- | ------------------------------------------------------------------- |
89
+ | User | `sdk.me` | `get`, `accounts` (list managed pages) |
90
+ | Page | `sdk.page(id).posts` | `list` |
91
+ | Page | `sdk.page(id).videos` / `.reels` | `list`, `publish` (with thumbnail + status polling) |
92
+ | Page | `sdk.page(id).images` | `publish` |
93
+ | Page | `sdk.page(id).comments` | `list` — aggregated across recent posts, store-accelerated |
94
+ | Page/Post | `.insights` | `list` — typed metrics → `{ timeSeries, total \| snapshot }` |
95
+ | Post | `sdk.post(id)` | `get`, `expire`, `comments`, `insights` |
96
+ | Comment | `sdk.comment(id)` | `get`, `update`, `delete`, `like`, `unlike`, `reply`, `replies` |
97
+ | Batch | `sdk.batch` | Up to 50 per request, auto-chunked |
98
+ | Webhook | `createWebhookHandler` | `handleVerify`, `handleEvent` — signature-verified, typed `onEvent` dispatch (FB + IG) |
99
+ | Stores | `createMemoryStore`, `createRedisStore` | In-process and Redis sorted-set backed |
100
+
101
+ Instagram is a **separate SDK** — `createInstagramSdk()(igToken)` — talking to `graph.instagram.com` (Instagram API with Instagram Login), fully decoupled from the Facebook token:
102
+
103
+ | Area | Resource | Operations |
104
+ | --------- | ------------------------------------------- | ------------------------------------------------------------------- |
105
+ | Account | `ig.account(id)` | `get`, `media` (publish/list), `insights`, `mentions`, `stories`, `tags` |
106
+ | Media | `ig.media(id)` | `get`, `insights`, `comments`, `setCommentEnabled` |
107
+ | Comment | `ig.comment(id)` | `get`, `reply`, `replies`, `hide`, `delete` |
108
+
109
+ Not covered yet: ads, business management, leadgen retrieval, messenger, marketing API, app events. PRs welcome — see [Contributing](#contributing).
110
+
111
+ ---
112
+
113
+ ## Core concepts
114
+
115
+ ### 1. Field selectors
116
+
117
+ Instead of building a Graph `fields=...` string by hand, you describe the shape you want as a plain object:
118
+
119
+ ```ts
120
+ const post = await sdk.post("123").get({
121
+ id: true,
122
+ message: true,
123
+ comments: {
124
+ fields: { id: true, message: true },
125
+ options: { limit: 10, order: ORDER.NEWEST },
126
+ },
127
+ });
128
+ ```
129
+
130
+ - Leaves are `true`.
131
+ - Plain object children (`{ summary: true }`) descend into nested fields.
132
+ - **Collection** fields use `{ fields, options? }`. `options` becomes Graph's `.limit(N).order(...)` syntax.
133
+ - Unknown keys are rejected at compile time. Selecting `id` does not give you `message` in the result type.
134
+
135
+ The selector is converted to a Graph string by [`toGraphFields`](src/internal/utils.ts):
136
+
137
+ ```
138
+ { id: true, comments: { fields: { id: true }, options: { limit: 5 } } }
139
+ → "id,comments.limit(5){id}"
140
+ ```
141
+
142
+ See [docs/type-system.md](docs/type-system.md) for the recursive types behind this (`FbFieldSelector`, `FbPickDeep`, `DeepStrict`, `Fields`).
143
+
144
+ ### 2. `BatchableRequest<T>` — one value, two uses
145
+
146
+ Every method on a resource returns a `BatchableRequest<T>`. It carries:
147
+
148
+ - `method` and `relative_url` — what the FB batch API needs to embed it in a batch.
149
+ - `then` / `catch` — so `await req` Just Works.
150
+ - `transform(fn)` — map the response in a way that survives batching.
151
+
152
+ ```ts
153
+ const idOnly = sdk.post("123").get({ id: true }).transform((p) => p.id);
154
+ // ^? BatchableRequest<string>
155
+
156
+ const id = await idOnly; // works
157
+ const [{ data: id2 }] = await sdk.batch([idOnly]); // also works
158
+ ```
159
+
160
+ `transform` is the trick that makes `sdk.batch([...])` return typed, post-processed data — the same transform runs in both code paths. See [docs/batching.md](docs/batching.md).
161
+
162
+ ### 3. camelCase everywhere
163
+
164
+ The SDK does case conversion in both directions, at both the runtime and the type level:
165
+
166
+ - Outgoing params and bodies: `toSnakeObj` / `toSnakeFormData` / `toSnakeCase` convert your camelCase keys before they hit the wire.
167
+ - Incoming responses: `toCamel` rewrites all keys recursively. The axios instance applies it as a global response transform.
168
+ - At the type level: `KeysToCamel<T>` and `KeysToSnake<T>` recursively transform key strings using template literal types, so `FacebookPostRaw` (snake) and `FacebookPost` (camel) stay in sync from a single source of truth.
169
+
170
+ ```ts
171
+ // You write:
172
+ sdk.page("me").posts.list({ fields: { id: true, createdTime: true } });
173
+ // Wire sees: fields=id,created_time
174
+ // You await: { data: { id: string; createdTime: string }[]; paging: ... }
175
+ ```
176
+
177
+ Keys starting with `_` are preserved by `KeysToCamel` (used for internal type-level markers like `_edgeOptions`).
178
+
179
+ ### 4. Batching
180
+
181
+ ```ts
182
+ const results = await sdk.batch([
183
+ sdk.post("a").get({ id: true }),
184
+ sdk.post("b").get({ id: true, message: true }),
185
+ sdk.comment("c").like(),
186
+ ]);
30
187
 
31
- // 1. Initialize the SDK factory (optionally pass configuration like a Store)
32
- const sdkFactory = createFbSdk();
188
+ // results is a tuple matching input order:
189
+ // [
190
+ // { status: 200; data: { id: string } },
191
+ // { status: 200; data: { id: string; message: string } },
192
+ // { status: 200; data: LikeCommentResponse },
193
+ // ]
194
+ ```
195
+
196
+ - Up to 50 requests per HTTP call. Larger arrays are chunked transparently.
197
+ - POSTs created from a JSON payload carry their body into the batch. FormData uploads can't be batched.
198
+ - Each result is `{ status, data }`. Non-200 responses leave `data` as the raw body string; sub-requests Facebook timed out come back as `{ status: 0, data: null }`.
199
+ - `includeHeaders` is opt-in.
200
+
201
+ ### 5. Page-level comment fan-out
202
+
203
+ The `sdk.page(id).comments.list(...)` resource is the one place the SDK does something more than a 1:1 Graph call — it aggregates comments across multiple posts. There are two modes:
204
+
205
+ - **Store-backed** (recommended): pass a `Store` in `createFbSdk({ store })` and run the webhook handler. The store remembers which posts had recent comment activity; `list({ options: { since } })` only fetches comments from those posts.
206
+ - **On-demand**: no store. The SDK pulls the latest posts on the page (`createFbSdk({ postsLimit })`, default 50, max 100) and fans out comments across them.
207
+
208
+ Pagination uses a base64url-encoded cursor that bundles per-post cursors so the caller sees a single opaque `after` token. See [docs/webhooks-and-stores.md](docs/webhooks-and-stores.md).
209
+
210
+ ---
33
211
 
34
- // 2. Instantiate the client with a Page or User Access Token
35
- const sdk = sdkFactory("EAAGYourAccessTokenHere...");
212
+ ## Webhooks
36
213
 
37
- async function run() {
38
- // Fetch a page's recent posts, selecting specific fields
39
- const posts = await sdk.page("PAGE_ID").posts.list({
40
- fields: {
41
- id: true,
42
- message: true,
43
- createdTime: true
44
- },
45
- options: {
46
- limit: 5
214
+ ```ts
215
+ import express from "express";
216
+ import {
217
+ createFbSdk,
218
+ createMemoryStore,
219
+ createWebhookHandler,
220
+ } from "@tabsircg/fb-sdk";
221
+
222
+ const store = createMemoryStore();
223
+ const sdk = createFbSdk({ store });
224
+
225
+ const webhook = createWebhookHandler({
226
+ verifyToken: process.env.FB_VERIFY_TOKEN!,
227
+ appSecret: process.env.FB_APP_SECRET!,
228
+ store, // optional — auto-records FB Page comment activity for store-accelerated reads
229
+ onEvent: async (event) => {
230
+ switch (event.type) {
231
+ case "comment.added":
232
+ // event.platform: "facebook" | "instagram" — narrow for the differing fields
233
+ if (event.platform === "instagram") {
234
+ await notify(event.mediaId, event.commentId, event.text);
235
+ } else {
236
+ await notify(event.postId, event.commentId, event.text);
237
+ }
238
+ break;
239
+ case "mention.created":
240
+ await flagMention(event);
241
+ break;
242
+ // comment.edited | comment.removed | comment.hidden | comment.unhidden
243
+ // post.published | reaction.added | reaction.removed
244
+ // review.created | review.updated | unknown
47
245
  }
48
- });
246
+ },
247
+ });
248
+
249
+ const app = express();
250
+ app.use(express.json({ verify: (req, _res, buf) => ((req as any).rawBody = buf) }));
251
+
252
+ app.get("/webhook", webhook.handleVerify);
253
+ app.post("/webhook", webhook.handleEvent);
254
+ ```
255
+
256
+ The handler:
257
+
258
+ - Verifies the `X-Hub-Signature-256` HMAC against `appSecret` (timing-safe), responds `200` immediately (Meta retries otherwise), then processes in the background.
259
+ - Parses **Facebook and Instagram** payloads — including both Instagram login shapes (flat `field`/`value` and nested `changes[]`) and the `from`/`sender_*` author variants — into one normalized, camelCase `WebhookEvent` union. Switch on `event.type`, narrow on `event.platform`.
260
+ - Delivers anything not modeled (DMs/messaging, `live_comments`, `story_insights`) as an `unknown` event with the original payload on `event.raw` — captured, never dropped.
261
+ - If a `store` is supplied, Facebook Page comment-adds are recorded automatically (`recordActivity`) so store-accelerated reads keep working — independent of `onEvent`.
262
+ - Routes background failures (store outages, a throwing `onEvent`) to the optional `onError` callback instead of crashing after the response is sent.
263
+
264
+ **Event types:** `comment.added` · `comment.edited` · `comment.removed` · `comment.hidden` · `comment.unhidden` · `post.published` · `reaction.added` · `reaction.removed` · `mention.created` · `review.created` · `review.updated` · `unknown`.
265
+
266
+ Then your reader uses the same store:
267
+
268
+ ```ts
269
+ // Only hits posts that had comments after `since`
270
+ const comments = await sdk.page(pageId).comments.list({
271
+ fields: {
272
+ id: true,
273
+ message: true,
274
+ post: { id: true, message: true, picture: true },
275
+ },
276
+ options: { since: Date.now() - 24 * 60 * 60 * 1000 },
277
+ });
278
+ ```
279
+
280
+ For multi-process deployments use the Redis store:
281
+
282
+ ```ts
283
+ import Redis from "ioredis";
284
+ import { createRedisStore } from "@tabsircg/fb-sdk";
285
+
286
+ const redis = new Redis(process.env.REDIS_URL!);
287
+ const store = createRedisStore(redis);
288
+ ```
289
+
290
+ `createRedisStore` accepts anything matching the `RedisLike` interface — `ioredis`, `node-redis` v4 with a thin adapter, or your own mock. It uses `ZADD GT` (Redis ≥ 6.2) so out-of-order webhook deliveries can't move activity timestamps backwards.
291
+
292
+ ---
293
+
294
+ ## Error handling
295
+
296
+ Pass an `onError` hook to `createFbSdk`. It runs after a response is received but **before** it is returned or thrown, whenever an error is detected — on direct requests *and* on individual batch sub-responses. It is purely observational: registering it never changes what the SDK throws or returns.
49
297
 
50
- console.log("Recent posts:", posts.data);
298
+ ```ts
299
+ import { createFbSdk } from "@tabsircg/fb-sdk";
51
300
 
52
- // Example: Publish a new image
53
- const publishTarget = await sdk.page("PAGE_ID").images.publish({
54
- url: "https://example.com/image.png",
55
- message: "Hello world!"
56
- });
57
-
58
- console.log("Published Post ID:", publishTarget.postId);
301
+ const sdk = createFbSdk({
302
+ // `ctx` identifies the failing call: { method, relativeUrl, accessToken, source }
303
+ onError: (err, ctx) => {
304
+ switch (err.category) {
305
+ case "auth": // token expired/revoked — ctx.accessToken is the page/channel key
306
+ markChannelRevoked(ctx.accessToken);
307
+ break;
308
+ case "rate_limit": // back off; usage headers say roughly for how long
309
+ logger.warn("throttled", err.usage?.appUsage);
310
+ break;
311
+ case "network": // timeout / DNS / transport — usually retryable
312
+ metrics.increment("fb.network_error");
313
+ break;
314
+ default:
315
+ logger.warn({ trace: err.traceId, call: `${ctx.method} ${ctx.relativeUrl}` }, err.message);
316
+ }
317
+ },
318
+ })(token);
319
+ ```
320
+
321
+ The hook receives two arguments: the typed error, and a `context` (`{ method, relativeUrl, accessToken, source }`) identifying *which* call failed. `accessToken` is the call's own token — for a multi-page app it's the unique key to the page/channel, so an `auth` error tells you exactly which channel to mark revoked. The second argument is optional to consume; `(err) => …` keeps working.
322
+
323
+ Error types and classes live at the **`@tabsircg/fb-sdk/errors`** subpath — kept off the main entry to keep it uncluttered. Inside the hook, `err` and `ctx` are inferred, so you often don't need to import anything.
324
+
325
+ The hook receives a strictly-typed `FacebookError` — a discriminated union you narrow on `.category`:
326
+
327
+ | category | when | retryable |
328
+ | --------------- | --------------------------------------------------------------- | --------------------- |
329
+ | `auth` | token expired/revoked/invalid (190, 102) | no — re-authenticate |
330
+ | `permission` | missing permission or Page role (10, 3, 200–299, 190+492) | no |
331
+ | `rate_limit` | throttled (4, 17, 32, 341, 613, 80000–80014); carries `usage` | yes — back off |
332
+ | `invalid_param` | bad request / params / object (100, 506, 1609005, …) | no |
333
+ | `policy_block` | integrity/abuse block (368) | after a wait |
334
+ | `transient` | temporary server error (1, 2, `is_transient`, or 5xx) | yes — immediate |
335
+ | `unknown` | a Graph envelope the SDK did not classify | inspect `code` / `raw`|
336
+ | `network` | no Graph envelope: timeout, DNS, non-JSON body, batch timeout | usually |
337
+
338
+ Every error carries `category`, `httpStatus`, `isTransient`, and `raw` (the unprocessed, camelized envelope — the escape hatch). Graph-envelope errors (everything except `network`) also carry `code`, `type`, `message`, and optional `subcode`, `traceId`, `userTitle`, `userMessage`.
339
+
340
+ Because Facebook's code space is open-ended and version-volatile, `code` and `subcode` stay plain `number` — never closed literal unions. Named constants are exported for the documented values:
341
+
342
+ ```ts
343
+ import { FacebookErrorCode, FacebookAuthSubcode } from "@tabsircg/fb-sdk/errors";
344
+
345
+ if (err.code === FacebookErrorCode.ACCESS_TOKEN && err.subcode === FacebookAuthSubcode.EXPIRED) {
346
+ // token expired
59
347
  }
348
+ ```
349
+
350
+ The error classes are exported from `@tabsircg/fb-sdk/errors` for `instanceof` checks — `FacebookErrorBase` (any SDK error), `FacebookGraphError` (any error carrying a Graph envelope), and the concrete per-category classes (`FacebookAuthError`, `FacebookRateLimitError`, …).
351
+
352
+ > The SDK still throws the original `AxiosError` for direct requests, and `sdk.batch([...])` still returns the same `{ status, data }` results — `onError` only *observes* them. A hook that throws or rejects is swallowed so it can never mask the underlying error.
60
353
 
61
- run().catch(console.error);
354
+ ---
355
+
356
+ ## Project layout
357
+
358
+ ```
359
+ src/
360
+ ├── client.ts Public entry — createFbSdk + re-exports
361
+ ├── errors.ts Public error surface ("@tabsircg/fb-sdk/errors")
362
+ ├── httpClient.ts Axios wrapper, request → BatchableRequest
363
+ ├── internal/
364
+ │ ├── batchable.ts createBatchableRequest, buildRelativeUrl
365
+ │ ├── fetchers.ts Page-level comment aggregator
366
+ │ ├── poller.ts poll() + pollVideoStatus / pollReelStatus
367
+ │ ├── error.ts FacebookUploadError + typed FacebookError model & hook
368
+ │ └── utils.ts toGraphFields (selector → Graph string)
369
+ ├── lib/
370
+ │ └── transformCase.ts toCamel / toSnake + KeysToCamel / KeysToSnake types
371
+ ├── resources/
372
+ │ ├── PageResource.ts videos, reels, images, posts (page sub-resources)
373
+ │ ├── PostResource.ts Single post, plus media node
374
+ │ ├── UserResource.ts /me, /me/accounts
375
+ │ ├── InsightResource.ts Page + post insights with typed metric maps
376
+ │ ├── createBatchResource.ts batch([...]) with 50-chunking
377
+ │ └── comment/
378
+ │ ├── CommentResource.ts Single-comment CRUD + reply
379
+ │ └── PageCommentResource.ts Cross-post aggregation
380
+ ├── store/
381
+ │ ├── types.ts Store interface
382
+ │ ├── memory.ts createMemoryStore
383
+ │ └── redis.ts createRedisStore + RedisLike interface
384
+ ├── webhook/
385
+ │ ├── handler.ts createWebhookHandler
386
+ │ └── normalize.ts raw payload → WebhookEvent[]
387
+ └── types/
388
+ ├── shared.ts FbFieldSelector, FbPickDeep, DeepStrict, BatchableRequest
389
+ ├── facebookpost.ts FacebookPost / Comment / write-op params
390
+ ├── facebookpage.ts FacebookPage
391
+ ├── facebookuser.ts FacebookUser
392
+ ├── facebookmedia.ts FacebookMedia + publish params
393
+ ├── facebookinsights.ts Page/Post metric maps, InsightResult shapes
394
+ └── webhook.ts Raw envelope + normalized WebhookEvent union
395
+
396
+ tests/
397
+ ├── unit/ vitest runtime tests
398
+ └── types/ expect-type compile-time tests (typecheck only)
399
+ ```
400
+
401
+ ---
402
+
403
+ ## Development
404
+
405
+ ```bash
406
+ pnpm install
407
+ pnpm lint # eslint (type-aware rules)
408
+ pnpm test # vitest — unit tests + compile-time type tests
409
+ pnpm check # lint + test
410
+ pnpm build # check, then tsc → dist/
62
411
  ```
63
412
 
64
- ## Common Errors & Fixes
413
+ - Unit tests: `tests/unit/*.test.ts` (vitest). `httpClientContract.test.ts` exercises the **real** axios pipeline via adapter injection — keep it green when touching `httpClient.ts` or `batchable.ts`.
414
+ - Type tests: `tests/types/*.test-d.ts` — typecheck only, using `expect-type`. They include `@ts-expect-error` markers to assert that invalid usages fail to compile. They run as part of `pnpm test`.
415
+ - Linting runs before anything ships: `build` (and therefore `prepublishOnly`) is `lint → test → tsc`.
416
+ - `tsconfig.json` is on the strict end: `exactOptionalPropertyTypes`, `noUncheckedIndexedAccess`, `noPropertyAccessFromIndexSignature`, `verbatimModuleSyntax` all on.
417
+
418
+ ---
419
+
420
+ ## Contributing
421
+
422
+ Bug reports, type-system gotchas, and PRs for missing Graph resources are all welcome. A few rough guidelines:
423
+
424
+ - Mirror the existing resource shape: a `createXResource({ http, id, config? })` factory returning typed methods that each produce a `BatchableRequest<T>`.
425
+ - Type the raw API shape as a `*Raw` interface (snake_case) and export the camelCase view as `KeysToCamel<*Raw>`. This is how every type stays in sync without duplication.
426
+ - Add a unit test under `tests/unit/` for runtime behaviour and a `.test-d.ts` under `tests/types/` for the type surface — especially `@ts-expect-error` cases for what *shouldn't* compile.
427
+ - Don't add retry / rate-limit logic without discussion; the current direction is to leave retries to the caller. The typed errors expose what a retry layer would need — `category` (`rate_limit`/`transient`/`policy_block` are retryable), `isTransient`, and `FacebookRateLimitError.usage`.
65
428
 
66
- **FacebookUploadError**
67
- - *Symptom:* The SDK throws an error during a video or reel upload, typically containing a `FacebookMedia["status"]` payload.
68
- - *Fix:* This is an asynchronous processing error on Facebook's side. The SDK polls the status of uploads. Inspect the error message (extracted via `getProcessingError` in `poller.ts`) which might indicate unsupported codecs, file size limits exceeded, or temporary Facebook outages.
429
+ ---
69
430
 
70
- **Batching Issues ("API Error code 2/3")**
71
- - *Symptom:* `sdk.batch([ ...requests ])` fails with a confusing Graph API error.
72
- - *Fix:* Ensure all requests inside the batch call were invoked without `await`. A `BatchableRequest` triggers a standard HTTP call if awaited, but returns `{ method, relative_url }` otherwise which the `batch` method leverages.
431
+ ## License
73
432
 
74
- **Type errors on `fields` selector**
75
- - *Symptom:* TypeScript complains when selecting nested fields like `comments: { ... }`.
76
- - *Fix:* Verify that the nested property is defined as an object or `CollectionOf<T>` in the type definitions (`src/types/`). Ensure you use the exact camelCase keys for fields (e.g., `createdTime` instead of `created_time`).
433
+ ISC.
package/dist/client.d.ts CHANGED
@@ -1,7 +1,10 @@
1
- import { HttpClient } from "./httpClient.js";
2
- import { Store } from "./client.js";
1
+ import { type HttpClient } from "./httpClient.js";
2
+ import type { Store } from "./store/types.js";
3
+ import type { FacebookErrorHook } from "./internal/error.js";
3
4
  export interface FbSdkConfig {
4
5
  store?: Store;
6
+ postsLimit?: number;
7
+ onError?: FacebookErrorHook;
5
8
  }
6
9
  export interface CreateResourceParams {
7
10
  http: HttpClient;
@@ -17,7 +20,7 @@ export declare function createFbSdk(config?: FbSdkConfig): (accessToken: string)
17
20
  create: import("./resources/comment/CommentResource.js").CreateComment;
18
21
  };
19
22
  insights: {
20
- list: <F extends import("./client.js").FbFieldSelector<{
23
+ list: <F extends import("./types/shared.js").FbFieldSelector<{
21
24
  postMediaView: {
22
25
  name: "post_media_view";
23
26
  values: {
@@ -295,7 +298,7 @@ export declare function createFbSdk(config?: FbSdkConfig): (accessToken: string)
295
298
  endTime?: string;
296
299
  }[];
297
300
  };
298
- }, 10>>(query: import("./client.js").InsightQuery<{
301
+ }, 10>>(query: import("./types/facebookinsights.js").InsightQuery<{
299
302
  postMediaView: {
300
303
  name: "post_media_view";
301
304
  values: {
@@ -573,7 +576,7 @@ export declare function createFbSdk(config?: FbSdkConfig): (accessToken: string)
573
576
  endTime?: string;
574
577
  }[];
575
578
  };
576
- }, F>) => import("./client.js").BatchableRequest<import("./client.js").InsightResponse<{
579
+ }, F>) => import("./types/shared.js").BatchableRequest<import("./types/facebookinsights.js").InsightResponse<{
577
580
  postMediaView: {
578
581
  name: "post_media_view";
579
582
  values: {
@@ -870,10 +873,10 @@ export declare function createFbSdk(config?: FbSdkConfig): (accessToken: string)
870
873
  list: import("./resources/PageResource.js").ListPosts;
871
874
  };
872
875
  comments: {
873
- list: import("./resources/comment/PageCommentResouorce.js").GetPageComments;
876
+ list: import("./resources/comment/PageCommentResource.js").GetPageComments;
874
877
  };
875
878
  insights: {
876
- list: <F extends import("./client.js").FbFieldSelector<{
879
+ list: <F extends import("./types/shared.js").FbFieldSelector<{
877
880
  pageMediaView: {
878
881
  name: "page_media_view";
879
882
  values: {
@@ -1136,7 +1139,7 @@ export declare function createFbSdk(config?: FbSdkConfig): (accessToken: string)
1136
1139
  endTime?: string;
1137
1140
  }[];
1138
1141
  };
1139
- }, 10>>(query: import("./client.js").InsightQuery<{
1142
+ }, 10>>(query: import("./types/facebookinsights.js").InsightQuery<{
1140
1143
  pageMediaView: {
1141
1144
  name: "page_media_view";
1142
1145
  values: {
@@ -1399,7 +1402,7 @@ export declare function createFbSdk(config?: FbSdkConfig): (accessToken: string)
1399
1402
  endTime?: string;
1400
1403
  }[];
1401
1404
  };
1402
- }, F>) => import("./client.js").BatchableRequest<import("./client.js").InsightResponse<{
1405
+ }, F>) => import("./types/shared.js").BatchableRequest<import("./types/facebookinsights.js").InsightResponse<{
1403
1406
  pageMediaView: {
1404
1407
  name: "page_media_view";
1405
1408
  values: {
@@ -1679,7 +1682,7 @@ export declare function createFbSdk(config?: FbSdkConfig): (accessToken: string)
1679
1682
  accounts: import("./resources/UserResource.js").ListAccounts;
1680
1683
  };
1681
1684
  http: HttpClient;
1682
- batch: <const T extends readonly import("./client.js").BatchSubRequest[]>(requests: T, options?: import("./resources/createBatchResource.js").BatchRequestOptions) => Promise<{ -readonly [K in keyof T]: T[K] extends import("./client.js").BatchableRequest<infer R> ? {
1685
+ batch: <const T extends readonly import("./types/shared.js").BatchSubRequest[]>(requests: T, batchOptions?: import("./resources/createBatchResource.js").BatchRequestOptions) => Promise<{ -readonly [K in keyof T]: T[K] extends import("./types/shared.js").BatchableRequest<infer R> ? {
1683
1686
  status: number;
1684
1687
  data: R;
1685
1688
  } : {
@@ -1687,15 +1690,21 @@ export declare function createFbSdk(config?: FbSdkConfig): (accessToken: string)
1687
1690
  data: any;
1688
1691
  }; }>;
1689
1692
  };
1693
+ export { createInstagramSdk } from "./instagramClient.js";
1694
+ export type { InstagramSdkConfig } from "./instagramClient.js";
1690
1695
  export { createMemoryStore } from "./store/memory.js";
1691
1696
  export { createRedisStore } from "./store/redis.js";
1692
1697
  export { createWebhookHandler } from "./webhook/handler.js";
1698
+ export { ORDER } from "./types/shared.js";
1699
+ export type { HttpClient } from "./httpClient.js";
1693
1700
  export type { Store } from "./store/types.js";
1694
1701
  export type { RedisLike } from "./store/redis.js";
1695
1702
  export type { WebhookHandlerConfig } from "./webhook/handler.js";
1696
1703
  export type { PageCommentConfig } from "./resources/comment/CommentResource.js";
1697
1704
  export type * from "./types/facebookinsights.js";
1698
1705
  export type * from "./types/facebookmedia.js";
1706
+ export type * from "./types/instagram.js";
1707
+ export type * from "./types/instagraminsights.js";
1699
1708
  export type * from "./types/facebookpage.js";
1700
1709
  export type * from "./types/facebookpost.js";
1701
1710
  export type * from "./types/facebookuser.js";
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAK/D,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAGpC,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,UAAU,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,wBAAgB,WAAW,CAAC,MAAM,GAAE,WAAgB,IAC1C,aAAa,MAAM;mBAGR,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBACN,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yBACA,MAAM;;;;;;;;;;;;;;;;;;;;;EAMhC;AAED,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,YAAY,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,YAAY,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAEhF,mBAAmB,6BAA6B,CAAC;AACjD,mBAAmB,0BAA0B,CAAC;AAC9C,mBAAmB,yBAAyB,CAAC;AAC7C,mBAAmB,yBAAyB,CAAC;AAC7C,mBAAmB,yBAAyB,CAAC;AAC7C,mBAAmB,mBAAmB,CAAC;AACvC,mBAAmB,oBAAoB,CAAC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js CHANGED
@@ -6,18 +6,20 @@ import { createCommentResource } from "./resources/comment/CommentResource.js";
6
6
  import { createBatchResource } from "./resources/createBatchResource.js";
7
7
  export function createFbSdk(config = {}) {
8
8
  return (accessToken) => {
9
- const http = createHttpClient(accessToken);
9
+ const http = createHttpClient(accessToken, { onError: config.onError });
10
10
  return {
11
11
  post: (postId) => createPostResource({ http, id: postId, config }),
12
12
  page: (pageId) => createPageResource({ http, id: pageId, config }),
13
13
  comment: (commentId) => createCommentResource({ http, id: commentId, config }),
14
14
  me: createUserResource({ http, config, id: "me" }),
15
15
  http,
16
- batch: createBatchResource(http),
16
+ batch: createBatchResource(http, { onError: config.onError }),
17
17
  };
18
18
  };
19
19
  }
20
+ export { createInstagramSdk } from "./instagramClient.js";
20
21
  export { createMemoryStore } from "./store/memory.js";
21
22
  export { createRedisStore } from "./store/redis.js";
22
23
  export { createWebhookHandler } from "./webhook/handler.js";
24
+ export { ORDER } from "./types/shared.js";
23
25
  //# sourceMappingURL=client.js.map