chub-dev 0.1.0 → 0.1.2-beta.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 (139) hide show
  1. package/README.md +55 -0
  2. package/bin/chub-mcp +2 -0
  3. package/dist/airtable/docs/database/javascript/DOC.md +1437 -0
  4. package/dist/airtable/docs/database/python/DOC.md +1735 -0
  5. package/dist/amplitude/docs/analytics/javascript/DOC.md +1282 -0
  6. package/dist/amplitude/docs/analytics/python/DOC.md +1199 -0
  7. package/dist/anthropic/docs/claude-api/javascript/DOC.md +503 -0
  8. package/dist/anthropic/docs/claude-api/python/DOC.md +389 -0
  9. package/dist/asana/docs/tasks/DOC.md +1396 -0
  10. package/dist/assemblyai/docs/transcription/DOC.md +1043 -0
  11. package/dist/atlassian/docs/confluence/javascript/DOC.md +1347 -0
  12. package/dist/atlassian/docs/confluence/python/DOC.md +1604 -0
  13. package/dist/auth0/docs/identity/javascript/DOC.md +968 -0
  14. package/dist/auth0/docs/identity/python/DOC.md +1199 -0
  15. package/dist/aws/docs/s3/javascript/DOC.md +1773 -0
  16. package/dist/aws/docs/s3/python/DOC.md +1807 -0
  17. package/dist/binance/docs/trading/javascript/DOC.md +1315 -0
  18. package/dist/binance/docs/trading/python/DOC.md +1454 -0
  19. package/dist/braintree/docs/gateway/javascript/DOC.md +1278 -0
  20. package/dist/braintree/docs/gateway/python/DOC.md +1179 -0
  21. package/dist/chromadb/docs/embeddings-db/javascript/DOC.md +1263 -0
  22. package/dist/chromadb/docs/embeddings-db/python/DOC.md +1707 -0
  23. package/dist/clerk/docs/auth/javascript/DOC.md +1220 -0
  24. package/dist/clerk/docs/auth/python/DOC.md +274 -0
  25. package/dist/cloudflare/docs/workers/javascript/DOC.md +918 -0
  26. package/dist/cloudflare/docs/workers/python/DOC.md +994 -0
  27. package/dist/cockroachdb/docs/distributed-db/DOC.md +1500 -0
  28. package/dist/cohere/docs/llm/DOC.md +1335 -0
  29. package/dist/datadog/docs/monitoring/javascript/DOC.md +1740 -0
  30. package/dist/datadog/docs/monitoring/python/DOC.md +1815 -0
  31. package/dist/deepgram/docs/speech/javascript/DOC.md +885 -0
  32. package/dist/deepgram/docs/speech/python/DOC.md +685 -0
  33. package/dist/deepl/docs/translation/javascript/DOC.md +887 -0
  34. package/dist/deepl/docs/translation/python/DOC.md +944 -0
  35. package/dist/deepseek/docs/llm/DOC.md +1220 -0
  36. package/dist/directus/docs/headless-cms/javascript/DOC.md +1128 -0
  37. package/dist/directus/docs/headless-cms/python/DOC.md +1276 -0
  38. package/dist/discord/docs/bot/javascript/DOC.md +1090 -0
  39. package/dist/discord/docs/bot/python/DOC.md +1130 -0
  40. package/dist/elasticsearch/docs/search/DOC.md +1634 -0
  41. package/dist/elevenlabs/docs/text-to-speech/javascript/DOC.md +336 -0
  42. package/dist/elevenlabs/docs/text-to-speech/python/DOC.md +552 -0
  43. package/dist/firebase/docs/auth/DOC.md +1015 -0
  44. package/dist/gemini/docs/genai/javascript/DOC.md +691 -0
  45. package/dist/gemini/docs/genai/python/DOC.md +555 -0
  46. package/dist/github/docs/octokit/DOC.md +1560 -0
  47. package/dist/google/docs/bigquery/javascript/DOC.md +1688 -0
  48. package/dist/google/docs/bigquery/python/DOC.md +1503 -0
  49. package/dist/hubspot/docs/crm/javascript/DOC.md +1805 -0
  50. package/dist/hubspot/docs/crm/python/DOC.md +2033 -0
  51. package/dist/huggingface/docs/transformers/DOC.md +948 -0
  52. package/dist/intercom/docs/messaging/javascript/DOC.md +1844 -0
  53. package/dist/intercom/docs/messaging/python/DOC.md +1797 -0
  54. package/dist/jira/docs/issues/javascript/DOC.md +1420 -0
  55. package/dist/jira/docs/issues/python/DOC.md +1492 -0
  56. package/dist/kafka/docs/streaming/javascript/DOC.md +1671 -0
  57. package/dist/kafka/docs/streaming/python/DOC.md +1464 -0
  58. package/dist/landingai-ade/docs/api/DOC.md +620 -0
  59. package/dist/landingai-ade/docs/sdk/python/DOC.md +489 -0
  60. package/dist/landingai-ade/docs/sdk/typescript/DOC.md +542 -0
  61. package/dist/landingai-ade/skills/SKILL.md +489 -0
  62. package/dist/launchdarkly/docs/feature-flags/javascript/DOC.md +1191 -0
  63. package/dist/launchdarkly/docs/feature-flags/python/DOC.md +1671 -0
  64. package/dist/linear/docs/tracker/DOC.md +1554 -0
  65. package/dist/livekit/docs/realtime/javascript/DOC.md +303 -0
  66. package/dist/livekit/docs/realtime/python/DOC.md +163 -0
  67. package/dist/mailchimp/docs/marketing/DOC.md +1420 -0
  68. package/dist/meilisearch/docs/search/DOC.md +1241 -0
  69. package/dist/microsoft/docs/onedrive/javascript/DOC.md +1421 -0
  70. package/dist/microsoft/docs/onedrive/python/DOC.md +1549 -0
  71. package/dist/mongodb/docs/atlas/DOC.md +2041 -0
  72. package/dist/notion/docs/workspace-api/javascript/DOC.md +1435 -0
  73. package/dist/notion/docs/workspace-api/python/DOC.md +1400 -0
  74. package/dist/okta/docs/identity/javascript/DOC.md +1171 -0
  75. package/dist/okta/docs/identity/python/DOC.md +1401 -0
  76. package/dist/openai/docs/chat/javascript/DOC.md +407 -0
  77. package/dist/openai/docs/chat/python/DOC.md +568 -0
  78. package/dist/paypal/docs/checkout/DOC.md +278 -0
  79. package/dist/pinecone/docs/sdk/javascript/DOC.md +984 -0
  80. package/dist/pinecone/docs/sdk/python/DOC.md +1395 -0
  81. package/dist/plaid/docs/banking/javascript/DOC.md +1163 -0
  82. package/dist/plaid/docs/banking/python/DOC.md +1203 -0
  83. package/dist/playwright-community/skills/login-flows/SKILL.md +108 -0
  84. package/dist/postmark/docs/transactional-email/DOC.md +1168 -0
  85. package/dist/prisma/docs/orm/javascript/DOC.md +1419 -0
  86. package/dist/prisma/docs/orm/python/DOC.md +1317 -0
  87. package/dist/qdrant/docs/vector-search/javascript/DOC.md +1221 -0
  88. package/dist/qdrant/docs/vector-search/python/DOC.md +1653 -0
  89. package/dist/rabbitmq/docs/message-queue/javascript/DOC.md +1193 -0
  90. package/dist/rabbitmq/docs/message-queue/python/DOC.md +1243 -0
  91. package/dist/razorpay/docs/payments/javascript/DOC.md +1219 -0
  92. package/dist/razorpay/docs/payments/python/DOC.md +1330 -0
  93. package/dist/redis/docs/key-value/javascript/DOC.md +1851 -0
  94. package/dist/redis/docs/key-value/python/DOC.md +2054 -0
  95. package/dist/registry.json +2817 -0
  96. package/dist/replicate/docs/model-hosting/DOC.md +1318 -0
  97. package/dist/resend/docs/email/DOC.md +1271 -0
  98. package/dist/salesforce/docs/crm/javascript/DOC.md +1241 -0
  99. package/dist/salesforce/docs/crm/python/DOC.md +1183 -0
  100. package/dist/search-index.json +1 -0
  101. package/dist/sendgrid/docs/email-api/javascript/DOC.md +371 -0
  102. package/dist/sendgrid/docs/email-api/python/DOC.md +656 -0
  103. package/dist/sentry/docs/error-tracking/javascript/DOC.md +1073 -0
  104. package/dist/sentry/docs/error-tracking/python/DOC.md +1309 -0
  105. package/dist/shopify/docs/storefront/DOC.md +457 -0
  106. package/dist/slack/docs/workspace/javascript/DOC.md +933 -0
  107. package/dist/slack/docs/workspace/python/DOC.md +271 -0
  108. package/dist/square/docs/payments/javascript/DOC.md +1855 -0
  109. package/dist/square/docs/payments/python/DOC.md +1728 -0
  110. package/dist/stripe/docs/api/DOC.md +1727 -0
  111. package/dist/stripe/docs/payments/DOC.md +1726 -0
  112. package/dist/stytch/docs/auth/javascript/DOC.md +1813 -0
  113. package/dist/stytch/docs/auth/python/DOC.md +1962 -0
  114. package/dist/supabase/docs/client/DOC.md +1606 -0
  115. package/dist/twilio/docs/messaging/python/DOC.md +469 -0
  116. package/dist/twilio/docs/messaging/typescript/DOC.md +946 -0
  117. package/dist/vercel/docs/platform/DOC.md +1940 -0
  118. package/dist/weaviate/docs/vector-db/javascript/DOC.md +1268 -0
  119. package/dist/weaviate/docs/vector-db/python/DOC.md +1388 -0
  120. package/dist/zendesk/docs/support/javascript/DOC.md +2150 -0
  121. package/dist/zendesk/docs/support/python/DOC.md +2297 -0
  122. package/package.json +22 -6
  123. package/skills/get-api-docs/SKILL.md +84 -0
  124. package/src/commands/annotate.js +83 -0
  125. package/src/commands/build.js +12 -1
  126. package/src/commands/feedback.js +150 -0
  127. package/src/commands/get.js +83 -42
  128. package/src/commands/search.js +7 -0
  129. package/src/index.js +43 -17
  130. package/src/lib/analytics.js +90 -0
  131. package/src/lib/annotations.js +57 -0
  132. package/src/lib/bm25.js +170 -0
  133. package/src/lib/cache.js +69 -6
  134. package/src/lib/config.js +8 -3
  135. package/src/lib/identity.js +99 -0
  136. package/src/lib/registry.js +103 -20
  137. package/src/lib/telemetry.js +86 -0
  138. package/src/mcp/server.js +177 -0
  139. package/src/mcp/tools.js +251 -0
@@ -0,0 +1,1347 @@
1
+ ---
2
+ name: confluence
3
+ description: "Confluence Cloud API coding guidelines for JavaScript/TypeScript using the confluence.js library"
4
+ metadata:
5
+ languages: "javascript"
6
+ versions: "2.1.0"
7
+ updated-on: "2026-03-02"
8
+ source: maintainer
9
+ tags: "atlassian,confluence,wiki,documentation,collaboration"
10
+ ---
11
+
12
+ # Confluence Cloud API Coding Guidelines (JavaScript/TypeScript)
13
+
14
+ You are a **Confluence Cloud API coding expert**. Help me write correct, idiomatic JavaScript/TypeScript that calls the Atlassian Confluence Cloud REST API using the confluence.js library.
15
+
16
+ Use **only official Atlassian sources** for API behavior, fields, and constraints. This guide summarizes key patterns for both **Node.js** and **browser** applications.
17
+
18
+ > Ground truth: Atlassian Confluence Cloud REST API documentation at developer.atlassian.com/cloud/confluence/
19
+
20
+ ## Golden Rule: Use confluence.js Library
21
+
22
+ **CRITICAL:** Use the `confluence.js` npm package (version 2.1.0 or later) for interacting with Confluence Cloud REST API. This is the most comprehensive and actively maintained community library for both Cloud and Server APIs.
23
+
24
+ **DO NOT use:**
25
+ - `confluence-api` (outdated, less comprehensive)
26
+ - `atlassian-confluence` (deprecated)
27
+ - Direct REST API calls without a client library (error-prone)
28
+
29
+ **Install:**
30
+ ```bash
31
+ npm install confluence.js
32
+ # or
33
+ yarn add confluence.js
34
+ # or
35
+ pnpm add confluence.js
36
+ ```
37
+
38
+ The library supports Node.js v20.0.0+ and modern browsers with full TypeScript support.
39
+
40
+ ## Authentication
41
+
42
+ Confluence Cloud supports multiple authentication methods. Choose based on your use case.
43
+
44
+ ### API Token (Basic Auth) - Recommended for Scripts
45
+
46
+ Generate an API token from your Atlassian Account Settings (https://id.atlassian.com/manage-profile/security/api-tokens).
47
+
48
+ ```ts
49
+ import { ConfluenceClient } from 'confluence.js';
50
+
51
+ const client = new ConfluenceClient({
52
+ host: 'https://your-domain.atlassian.net/wiki',
53
+ authentication: {
54
+ basic: {
55
+ email: 'your-email@example.com',
56
+ apiToken: process.env.CONFLUENCE_API_TOKEN,
57
+ },
58
+ },
59
+ });
60
+ ```
61
+
62
+ **Environment Variable Setup:**
63
+
64
+ ```bash
65
+ # .env file
66
+ CONFLUENCE_API_TOKEN=your_api_token_here
67
+ CONFLUENCE_EMAIL=your-email@example.com
68
+ CONFLUENCE_HOST=https://your-domain.atlassian.net/wiki
69
+ ```
70
+
71
+ **Loading in code:**
72
+
73
+ ```ts
74
+ import { config } from 'dotenv';
75
+ import { ConfluenceClient } from 'confluence.js';
76
+
77
+ config(); // Load .env file
78
+
79
+ const client = new ConfluenceClient({
80
+ host: process.env.CONFLUENCE_HOST!,
81
+ authentication: {
82
+ basic: {
83
+ email: process.env.CONFLUENCE_EMAIL!,
84
+ apiToken: process.env.CONFLUENCE_API_TOKEN!,
85
+ },
86
+ },
87
+ });
88
+ ```
89
+
90
+ ### OAuth 2.0 (3LO) - For Third-Party Apps
91
+
92
+ Use OAuth 2.0 three-legged authentication for apps that access Confluence on behalf of users.
93
+
94
+ ```ts
95
+ import { ConfluenceClient } from 'confluence.js';
96
+
97
+ const client = new ConfluenceClient({
98
+ host: 'https://your-domain.atlassian.net/wiki',
99
+ authentication: {
100
+ oauth2: {
101
+ accessToken: process.env.OAUTH_ACCESS_TOKEN!,
102
+ },
103
+ },
104
+ });
105
+ ```
106
+
107
+ ### JWT (Server-to-Server) - For Atlassian Connect Apps
108
+
109
+ ```ts
110
+ import { ConfluenceClient } from 'confluence.js';
111
+
112
+ const client = new ConfluenceClient({
113
+ host: 'https://your-domain.atlassian.net/wiki',
114
+ authentication: {
115
+ jwt: {
116
+ issuer: process.env.JWT_ISSUER!,
117
+ secret: process.env.JWT_SECRET!,
118
+ expiryTimeSeconds: 180, // Optional, defaults to 180
119
+ },
120
+ },
121
+ });
122
+ ```
123
+
124
+ ## Initialization Patterns
125
+
126
+ ### Basic Initialization
127
+
128
+ ```ts
129
+ import { ConfluenceClient } from 'confluence.js';
130
+
131
+ const client = new ConfluenceClient({
132
+ host: 'https://your-domain.atlassian.net/wiki',
133
+ authentication: {
134
+ basic: {
135
+ email: 'your-email@example.com',
136
+ apiToken: 'your-api-token',
137
+ },
138
+ },
139
+ });
140
+ ```
141
+
142
+ ### With Custom API Prefix
143
+
144
+ If your Confluence instance uses a non-standard API path:
145
+
146
+ ```ts
147
+ const client = new ConfluenceClient({
148
+ host: 'https://your-domain.atlassian.net',
149
+ apiPrefix: '/custom/api/path',
150
+ authentication: {
151
+ basic: {
152
+ email: 'your-email@example.com',
153
+ apiToken: 'your-api-token',
154
+ },
155
+ },
156
+ });
157
+ ```
158
+
159
+ ### Tree Shaking for Smaller Bundles
160
+
161
+ Import only the API modules you need:
162
+
163
+ ```ts
164
+ import { ContentClient } from 'confluence.js/out/api/content';
165
+ import { SpaceClient } from 'confluence.js/out/api/space';
166
+
167
+ // Use individual clients
168
+ const contentClient = new ContentClient({
169
+ host: 'https://your-domain.atlassian.net/wiki',
170
+ authentication: { /* ... */ },
171
+ });
172
+ ```
173
+
174
+ ## Pages API
175
+
176
+ ### Get Page by ID
177
+
178
+ ```ts
179
+ const page = await client.content.getContent({
180
+ id: '123456789',
181
+ expand: ['body.storage', 'version', 'space'],
182
+ });
183
+
184
+ console.log(page.title);
185
+ console.log(page.body?.storage?.value);
186
+ console.log(page.version?.number);
187
+ ```
188
+
189
+ ### Get Page by Title and Space
190
+
191
+ ```ts
192
+ const results = await client.content.getContent({
193
+ spaceKey: 'DEMO',
194
+ title: 'Project Overview',
195
+ expand: ['body.storage', 'version'],
196
+ });
197
+
198
+ if (results.results && results.results.length > 0) {
199
+ const page = results.results[0];
200
+ console.log(page.id, page.title);
201
+ }
202
+ ```
203
+
204
+ ### Create a Page
205
+
206
+ ```ts
207
+ const newPage = await client.content.createContent({
208
+ type: 'page',
209
+ title: 'Getting Started Guide',
210
+ space: { key: 'DEMO' },
211
+ body: {
212
+ storage: {
213
+ value: '<h1>Welcome</h1><p>This is the introduction to our project.</p>',
214
+ representation: 'storage',
215
+ },
216
+ },
217
+ });
218
+
219
+ console.log(`Created page: ${newPage.id}`);
220
+ console.log(`URL: ${newPage._links?.webui}`);
221
+ ```
222
+
223
+ ### Create a Child Page
224
+
225
+ ```ts
226
+ const childPage = await client.content.createContent({
227
+ type: 'page',
228
+ title: 'Installation Instructions',
229
+ space: { key: 'DEMO' },
230
+ ancestors: [{ id: '123456789' }], // Parent page ID
231
+ body: {
232
+ storage: {
233
+ value: '<p>Follow these steps to install...</p>',
234
+ representation: 'storage',
235
+ },
236
+ },
237
+ });
238
+ ```
239
+
240
+ ### Update a Page
241
+
242
+ **IMPORTANT:** Always increment the version number when updating.
243
+
244
+ ```ts
245
+ // First, get the current page to retrieve version
246
+ const currentPage = await client.content.getContent({
247
+ id: '123456789',
248
+ expand: ['version'],
249
+ });
250
+
251
+ // Update with incremented version
252
+ const updatedPage = await client.content.updateContent({
253
+ id: '123456789',
254
+ type: 'page',
255
+ title: 'Updated Title',
256
+ version: {
257
+ number: currentPage.version!.number! + 1,
258
+ },
259
+ body: {
260
+ storage: {
261
+ value: '<h1>Updated Content</h1><p>New information here.</p>',
262
+ representation: 'storage',
263
+ },
264
+ },
265
+ });
266
+
267
+ console.log(`Updated to version ${updatedPage.version?.number}`);
268
+ ```
269
+
270
+ ### Update Only Page Content (Keep Title)
271
+
272
+ ```ts
273
+ const currentPage = await client.content.getContent({
274
+ id: '123456789',
275
+ expand: ['version', 'space'],
276
+ });
277
+
278
+ const updatedPage = await client.content.updateContent({
279
+ id: '123456789',
280
+ type: 'page',
281
+ title: currentPage.title, // Keep existing title
282
+ space: { key: currentPage.space?.key },
283
+ version: {
284
+ number: currentPage.version!.number! + 1,
285
+ },
286
+ body: {
287
+ storage: {
288
+ value: '<p>Only the content changed.</p>',
289
+ representation: 'storage',
290
+ },
291
+ },
292
+ });
293
+ ```
294
+
295
+ ### Delete a Page
296
+
297
+ ```ts
298
+ await client.content.deleteContent({ id: '123456789' });
299
+ console.log('Page deleted successfully');
300
+ ```
301
+
302
+ ### Get Page Children
303
+
304
+ ```ts
305
+ const children = await client.content.getContentChildren({
306
+ id: '123456789',
307
+ expand: ['page'],
308
+ });
309
+
310
+ if (children.page?.results) {
311
+ for (const child of children.page.results) {
312
+ console.log(`Child: ${child.title} (${child.id})`);
313
+ }
314
+ }
315
+ ```
316
+
317
+ ### Get Page History
318
+
319
+ ```ts
320
+ const history = await client.content.getHistory({ id: '123456789' });
321
+
322
+ console.log(`Created by: ${history.createdBy?.displayName}`);
323
+ console.log(`Created at: ${history.createdDate}`);
324
+ console.log(`Latest version: ${history.latest?.number}`);
325
+ ```
326
+
327
+ ### Get Page Versions
328
+
329
+ ```ts
330
+ const versions = await client.content.getContentVersions({
331
+ id: '123456789',
332
+ limit: 10,
333
+ });
334
+
335
+ for (const version of versions.results || []) {
336
+ console.log(`Version ${version.number} by ${version.by?.displayName}`);
337
+ console.log(` When: ${version.when}`);
338
+ console.log(` Message: ${version.message || 'No message'}`);
339
+ }
340
+ ```
341
+
342
+ ## Spaces API
343
+
344
+ ### Get Space by Key
345
+
346
+ ```ts
347
+ const space = await client.space.getSpace({
348
+ spaceKey: 'DEMO',
349
+ expand: ['description.plain', 'homepage'],
350
+ });
351
+
352
+ console.log(space.name);
353
+ console.log(space.description?.plain?.value);
354
+ console.log(space.homepage?.id);
355
+ ```
356
+
357
+ ### Get All Spaces
358
+
359
+ ```ts
360
+ const spaces = await client.space.getSpaces({
361
+ limit: 50,
362
+ expand: ['description.plain'],
363
+ });
364
+
365
+ for (const space of spaces.results || []) {
366
+ console.log(`${space.key}: ${space.name}`);
367
+ }
368
+ ```
369
+
370
+ ### Get Spaces with Pagination
371
+
372
+ ```ts
373
+ let start = 0;
374
+ const limit = 25;
375
+ let hasMore = true;
376
+
377
+ while (hasMore) {
378
+ const spaces = await client.space.getSpaces({
379
+ start,
380
+ limit,
381
+ });
382
+
383
+ for (const space of spaces.results || []) {
384
+ console.log(`${space.key}: ${space.name}`);
385
+ }
386
+
387
+ start += limit;
388
+ hasMore = (spaces.results?.length || 0) === limit;
389
+ }
390
+ ```
391
+
392
+ ### Create a Space
393
+
394
+ ```ts
395
+ const newSpace = await client.space.createSpace({
396
+ key: 'PROJ',
397
+ name: 'Project Galaxy',
398
+ description: {
399
+ plain: {
400
+ value: 'Documentation for Project Galaxy',
401
+ representation: 'plain',
402
+ },
403
+ },
404
+ });
405
+
406
+ console.log(`Created space: ${newSpace.key}`);
407
+ console.log(`URL: ${newSpace._links?.webui}`);
408
+ ```
409
+
410
+ ### Create a Private Space
411
+
412
+ ```ts
413
+ const privateSpace = await client.space.createPrivateSpace({
414
+ key: 'PRIV',
415
+ name: 'Private Team Space',
416
+ description: {
417
+ plain: {
418
+ value: 'Internal team documentation',
419
+ representation: 'plain',
420
+ },
421
+ },
422
+ });
423
+ ```
424
+
425
+ ### Update a Space
426
+
427
+ ```ts
428
+ const updatedSpace = await client.space.updateSpace({
429
+ spaceKey: 'DEMO',
430
+ name: 'Demo Space - Updated',
431
+ description: {
432
+ plain: {
433
+ value: 'Updated description',
434
+ representation: 'plain',
435
+ },
436
+ },
437
+ });
438
+ ```
439
+
440
+ ### Delete a Space
441
+
442
+ ```ts
443
+ const task = await client.space.deleteSpace({ spaceKey: 'OLDSPACE' });
444
+ console.log('Space deletion initiated');
445
+ ```
446
+
447
+ ### Get Space Content
448
+
449
+ ```ts
450
+ const content = await client.space.getSpaceContent({
451
+ spaceKey: 'DEMO',
452
+ expand: ['body.storage'],
453
+ limit: 50,
454
+ });
455
+
456
+ for (const item of content.page?.results || []) {
457
+ console.log(`Page: ${item.title} (${item.id})`);
458
+ }
459
+ ```
460
+
461
+ ## Search API
462
+
463
+ ### Search Content (CQL)
464
+
465
+ Use Confluence Query Language (CQL) for powerful searches:
466
+
467
+ ```ts
468
+ const results = await client.search.search({
469
+ cql: 'type=page AND space=DEMO AND title~"getting started"',
470
+ limit: 20,
471
+ expand: ['content.space', 'content.version'],
472
+ });
473
+
474
+ for (const result of results.results || []) {
475
+ console.log(`${result.content?.title} - ${result.content?.id}`);
476
+ }
477
+ ```
478
+
479
+ ### Common CQL Patterns
480
+
481
+ ```ts
482
+ // Find pages in a space
483
+ const pagesInSpace = await client.search.search({
484
+ cql: 'type=page AND space=DEMO',
485
+ });
486
+
487
+ // Find pages by creator
488
+ const myPages = await client.search.search({
489
+ cql: 'type=page AND creator=currentUser()',
490
+ });
491
+
492
+ // Find recently modified content
493
+ const recent = await client.search.search({
494
+ cql: 'type=page AND lastModified > now("-7d") ORDER BY lastModified DESC',
495
+ limit: 10,
496
+ });
497
+
498
+ // Find pages with specific label
499
+ const tagged = await client.search.search({
500
+ cql: 'type=page AND label="documentation"',
501
+ });
502
+
503
+ // Complex search with AND/OR
504
+ const complex = await client.search.search({
505
+ cql: 'type=page AND space IN (DEMO, PROJ) AND (title~"guide" OR text~"tutorial")',
506
+ });
507
+ ```
508
+
509
+ ### Search by Title
510
+
511
+ ```ts
512
+ const results = await client.search.searchContent({
513
+ title: 'Installation',
514
+ limit: 10,
515
+ });
516
+ ```
517
+
518
+ ## Attachments API
519
+
520
+ ### Get Attachments for Page
521
+
522
+ ```ts
523
+ const attachments = await client.content.getAttachments({
524
+ id: '123456789',
525
+ limit: 50,
526
+ });
527
+
528
+ for (const attachment of attachments.results || []) {
529
+ console.log(`${attachment.title} - ${attachment.extensions?.fileSize} bytes`);
530
+ console.log(`Download: ${attachment._links?.download}`);
531
+ }
532
+ ```
533
+
534
+ ### Upload an Attachment
535
+
536
+ ```ts
537
+ import fs from 'fs';
538
+ import FormData from 'form-data';
539
+
540
+ const form = new FormData();
541
+ form.append('file', fs.createReadStream('/path/to/file.pdf'), 'file.pdf');
542
+ form.append('comment', 'Uploaded via API');
543
+
544
+ const attachment = await client.content.createAttachment({
545
+ id: '123456789',
546
+ formData: form,
547
+ });
548
+
549
+ console.log(`Uploaded: ${attachment.results?.[0]?.title}`);
550
+ ```
551
+
552
+ ### Update an Existing Attachment
553
+
554
+ ```ts
555
+ const form = new FormData();
556
+ form.append('file', fs.createReadStream('/path/to/updated-file.pdf'), 'file.pdf');
557
+ form.append('comment', 'Updated version');
558
+
559
+ const updated = await client.content.updateAttachment({
560
+ id: '123456789',
561
+ attachmentId: '987654321',
562
+ formData: form,
563
+ });
564
+ ```
565
+
566
+ ### Download an Attachment
567
+
568
+ ```ts
569
+ // Get attachment metadata first
570
+ const attachments = await client.content.getAttachments({
571
+ id: '123456789',
572
+ });
573
+
574
+ const attachment = attachments.results?.[0];
575
+ if (attachment) {
576
+ const downloadUrl = `https://your-domain.atlassian.net${attachment._links?.download}`;
577
+ // Use fetch or axios to download
578
+ console.log(`Download from: ${downloadUrl}`);
579
+ }
580
+ ```
581
+
582
+ ## Labels API
583
+
584
+ ### Get Labels for Content
585
+
586
+ ```ts
587
+ const labels = await client.content.getLabels({ id: '123456789' });
588
+
589
+ for (const label of labels.results || []) {
590
+ console.log(`Label: ${label.name}`);
591
+ }
592
+ ```
593
+
594
+ ### Add Labels to Content
595
+
596
+ ```ts
597
+ const newLabels = await client.content.addLabels({
598
+ id: '123456789',
599
+ labels: [
600
+ { name: 'documentation' },
601
+ { name: 'getting-started' },
602
+ { name: 'tutorial' },
603
+ ],
604
+ });
605
+ ```
606
+
607
+ ### Remove a Label
608
+
609
+ ```ts
610
+ await client.content.removeLabel({
611
+ id: '123456789',
612
+ label: 'old-label',
613
+ });
614
+ ```
615
+
616
+ ## Comments API
617
+
618
+ ### Get Comments for Page
619
+
620
+ ```ts
621
+ const comments = await client.content.getContentComments({
622
+ id: '123456789',
623
+ expand: ['body.storage'],
624
+ limit: 50,
625
+ });
626
+
627
+ for (const comment of comments.results || []) {
628
+ console.log(`Comment by ${comment.history?.createdBy?.displayName}:`);
629
+ console.log(comment.body?.storage?.value);
630
+ }
631
+ ```
632
+
633
+ ### Add a Comment
634
+
635
+ ```ts
636
+ const comment = await client.content.createContent({
637
+ type: 'comment',
638
+ container: { id: '123456789', type: 'page' },
639
+ body: {
640
+ storage: {
641
+ value: '<p>This is a helpful comment!</p>',
642
+ representation: 'storage',
643
+ },
644
+ },
645
+ });
646
+ ```
647
+
648
+ ## User and Group APIs
649
+
650
+ ### Get Current User
651
+
652
+ ```ts
653
+ const user = await client.user.getCurrentUser();
654
+ console.log(`Logged in as: ${user.displayName} (${user.email})`);
655
+ ```
656
+
657
+ ### Get User by Account ID
658
+
659
+ ```ts
660
+ const user = await client.user.getUser({
661
+ accountId: '5a1234567890123456789012',
662
+ });
663
+ console.log(user.displayName);
664
+ ```
665
+
666
+ ### Get Group Members
667
+
668
+ ```ts
669
+ const members = await client.group.getMembers({
670
+ name: 'confluence-administrators',
671
+ limit: 50,
672
+ });
673
+
674
+ for (const member of members.results || []) {
675
+ console.log(member.displayName);
676
+ }
677
+ ```
678
+
679
+ ## Content Properties (Metadata)
680
+
681
+ ### Get Content Property
682
+
683
+ ```ts
684
+ const property = await client.content.getContentProperty({
685
+ id: '123456789',
686
+ key: 'custom-metadata',
687
+ });
688
+
689
+ console.log(property.value);
690
+ ```
691
+
692
+ ### Set Content Property
693
+
694
+ ```ts
695
+ await client.content.createContentProperty({
696
+ id: '123456789',
697
+ key: 'custom-metadata',
698
+ value: {
699
+ lastReviewed: '2025-11-07',
700
+ reviewer: 'john.doe@example.com',
701
+ status: 'approved',
702
+ },
703
+ });
704
+ ```
705
+
706
+ ### Update Content Property
707
+
708
+ ```ts
709
+ const current = await client.content.getContentProperty({
710
+ id: '123456789',
711
+ key: 'custom-metadata',
712
+ });
713
+
714
+ await client.content.updateContentProperty({
715
+ id: '123456789',
716
+ key: 'custom-metadata',
717
+ version: {
718
+ number: current.version!.number! + 1,
719
+ },
720
+ value: {
721
+ ...current.value,
722
+ status: 'needs-review',
723
+ },
724
+ });
725
+ ```
726
+
727
+ ### Delete Content Property
728
+
729
+ ```ts
730
+ await client.content.deleteContentProperty({
731
+ id: '123456789',
732
+ key: 'custom-metadata',
733
+ });
734
+ ```
735
+
736
+ ## Advanced Content Operations
737
+
738
+ ### Get Content Descendants
739
+
740
+ ```ts
741
+ const descendants = await client.content.getContentDescendants({
742
+ id: '123456789',
743
+ expand: ['page'],
744
+ });
745
+
746
+ console.log('All descendant pages:');
747
+ for (const page of descendants.page?.results || []) {
748
+ console.log(` ${page.title} (${page.id})`);
749
+ }
750
+ ```
751
+
752
+ ### Copy a Page
753
+
754
+ ```ts
755
+ const original = await client.content.getContent({
756
+ id: '123456789',
757
+ expand: ['body.storage', 'space'],
758
+ });
759
+
760
+ const copy = await client.content.createContent({
761
+ type: 'page',
762
+ title: `${original.title} (Copy)`,
763
+ space: { key: original.space?.key },
764
+ body: original.body,
765
+ });
766
+ ```
767
+
768
+ ### Move a Page to Different Parent
769
+
770
+ ```ts
771
+ const page = await client.content.getContent({
772
+ id: '123456789',
773
+ expand: ['version', 'space', 'ancestors'],
774
+ });
775
+
776
+ await client.content.updateContent({
777
+ id: '123456789',
778
+ type: 'page',
779
+ title: page.title,
780
+ space: { key: page.space?.key },
781
+ version: {
782
+ number: page.version!.number! + 1,
783
+ },
784
+ ancestors: [{ id: 'new-parent-id' }],
785
+ body: page.body,
786
+ });
787
+ ```
788
+
789
+ ### Archive a Page
790
+
791
+ ```ts
792
+ await client.content.archivePage({ id: '123456789' });
793
+ console.log('Page archived');
794
+ ```
795
+
796
+ ### Restore from Trash
797
+
798
+ ```ts
799
+ const restored = await client.content.restore({
800
+ id: '123456789',
801
+ });
802
+ console.log('Page restored');
803
+ ```
804
+
805
+ ## Content Restrictions (Permissions)
806
+
807
+ ### Get Content Restrictions
808
+
809
+ ```ts
810
+ const restrictions = await client.content.getContentRestrictions({
811
+ id: '123456789',
812
+ expand: ['read.restrictions.user', 'update.restrictions.user'],
813
+ });
814
+
815
+ console.log('Read restrictions:', restrictions.read);
816
+ console.log('Update restrictions:', restrictions.update);
817
+ ```
818
+
819
+ ### Add Read Restriction
820
+
821
+ ```ts
822
+ await client.content.addContentRestriction({
823
+ id: '123456789',
824
+ operation: 'read',
825
+ restrictions: {
826
+ user: [
827
+ { accountId: '5a1234567890123456789012' },
828
+ ],
829
+ group: [
830
+ { name: 'confluence-users' },
831
+ ],
832
+ },
833
+ });
834
+ ```
835
+
836
+ ### Remove All Restrictions
837
+
838
+ ```ts
839
+ await client.content.deleteContentRestriction({
840
+ id: '123456789',
841
+ operation: 'read',
842
+ });
843
+
844
+ await client.content.deleteContentRestriction({
845
+ id: '123456789',
846
+ operation: 'update',
847
+ });
848
+ ```
849
+
850
+ ## Macros in Content
851
+
852
+ ### Insert a Table of Contents Macro
853
+
854
+ ```ts
855
+ const page = await client.content.createContent({
856
+ type: 'page',
857
+ title: 'Documentation Index',
858
+ space: { key: 'DEMO' },
859
+ body: {
860
+ storage: {
861
+ value: `
862
+ <h1>Table of Contents</h1>
863
+ <ac:structured-macro ac:name="toc" ac:schema-version="1">
864
+ <ac:parameter ac:name="maxLevel">3</ac:parameter>
865
+ </ac:structured-macro>
866
+ <h2>Section 1</h2>
867
+ <p>Content here...</p>
868
+ `,
869
+ representation: 'storage',
870
+ },
871
+ },
872
+ });
873
+ ```
874
+
875
+ ### Insert a Status Macro
876
+
877
+ ```ts
878
+ const content = `
879
+ <p>Project status:
880
+ <ac:structured-macro ac:name="status" ac:schema-version="1">
881
+ <ac:parameter ac:name="colour">Green</ac:parameter>
882
+ <ac:parameter ac:name="title">Active</ac:parameter>
883
+ </ac:structured-macro>
884
+ </p>
885
+ `;
886
+ ```
887
+
888
+ ### Insert a Code Block Macro
889
+
890
+ ```ts
891
+ const content = `
892
+ <ac:structured-macro ac:name="code" ac:schema-version="1">
893
+ <ac:parameter ac:name="language">javascript</ac:parameter>
894
+ <ac:plain-text-body><![CDATA[
895
+ const greeting = 'Hello, World!';
896
+ console.log(greeting);
897
+ ]]></ac:plain-text-body>
898
+ </ac:structured-macro>
899
+ `;
900
+ ```
901
+
902
+ ### Insert an Info Panel Macro
903
+
904
+ ```ts
905
+ const content = `
906
+ <ac:structured-macro ac:name="info" ac:schema-version="1">
907
+ <ac:rich-text-body>
908
+ <p>This is important information for users to know.</p>
909
+ </ac:rich-text-body>
910
+ </ac:structured-macro>
911
+ `;
912
+ ```
913
+
914
+ ## Error Handling
915
+
916
+ ### Basic Error Handling
917
+
918
+ ```ts
919
+ try {
920
+ const page = await client.content.getContent({ id: 'invalid-id' });
921
+ } catch (error) {
922
+ if (error.response) {
923
+ console.error('Status:', error.response.status);
924
+ console.error('Message:', error.response.data?.message);
925
+ } else {
926
+ console.error('Error:', error.message);
927
+ }
928
+ }
929
+ ```
930
+
931
+ ### Common HTTP Status Codes
932
+
933
+ - `400 Bad Request`: Invalid parameters or request body
934
+ - `401 Unauthorized`: Invalid or missing authentication
935
+ - `403 Forbidden`: Insufficient permissions
936
+ - `404 Not Found`: Content or space does not exist
937
+ - `409 Conflict`: Version conflict (update with wrong version number)
938
+ - `429 Too Many Requests`: Rate limit exceeded
939
+
940
+ ### Handling Version Conflicts
941
+
942
+ ```ts
943
+ async function updatePageWithRetry(pageId: string, newContent: string, maxRetries = 3) {
944
+ for (let i = 0; i < maxRetries; i++) {
945
+ try {
946
+ const page = await client.content.getContent({
947
+ id: pageId,
948
+ expand: ['version', 'space'],
949
+ });
950
+
951
+ const updated = await client.content.updateContent({
952
+ id: pageId,
953
+ type: 'page',
954
+ title: page.title,
955
+ space: { key: page.space?.key },
956
+ version: {
957
+ number: page.version!.number! + 1,
958
+ },
959
+ body: {
960
+ storage: {
961
+ value: newContent,
962
+ representation: 'storage',
963
+ },
964
+ },
965
+ });
966
+
967
+ return updated;
968
+ } catch (error) {
969
+ if (error.response?.status === 409 && i < maxRetries - 1) {
970
+ console.log(`Conflict detected, retrying (${i + 1}/${maxRetries})...`);
971
+ await new Promise(resolve => setTimeout(resolve, 1000));
972
+ continue;
973
+ }
974
+ throw error;
975
+ }
976
+ }
977
+ }
978
+ ```
979
+
980
+ ### Rate Limit Handling
981
+
982
+ ```ts
983
+ async function apiCallWithBackoff<T>(
984
+ apiCall: () => Promise<T>,
985
+ maxRetries = 5
986
+ ): Promise<T> {
987
+ for (let i = 0; i < maxRetries; i++) {
988
+ try {
989
+ return await apiCall();
990
+ } catch (error) {
991
+ if (error.response?.status === 429 && i < maxRetries - 1) {
992
+ const retryAfter = error.response.headers['retry-after'] || Math.pow(2, i);
993
+ console.log(`Rate limited, waiting ${retryAfter}s before retry...`);
994
+ await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
995
+ continue;
996
+ }
997
+ throw error;
998
+ }
999
+ }
1000
+ throw new Error('Max retries exceeded');
1001
+ }
1002
+
1003
+ // Usage
1004
+ const page = await apiCallWithBackoff(() =>
1005
+ client.content.getContent({ id: '123456789' })
1006
+ );
1007
+ ```
1008
+
1009
+ ## Bulk Operations
1010
+
1011
+ ### Get Multiple Pages by IDs
1012
+
1013
+ ```ts
1014
+ async function getPagesByIds(pageIds: string[]) {
1015
+ const pages = await Promise.all(
1016
+ pageIds.map(id =>
1017
+ client.content.getContent({
1018
+ id,
1019
+ expand: ['body.storage', 'version']
1020
+ })
1021
+ )
1022
+ );
1023
+ return pages;
1024
+ }
1025
+ ```
1026
+
1027
+ ### Batch Create Pages
1028
+
1029
+ ```ts
1030
+ async function createMultiplePages(
1031
+ spaceKey: string,
1032
+ pageData: Array<{ title: string; content: string }>
1033
+ ) {
1034
+ const created = [];
1035
+
1036
+ for (const { title, content } of pageData) {
1037
+ const page = await client.content.createContent({
1038
+ type: 'page',
1039
+ title,
1040
+ space: { key: spaceKey },
1041
+ body: {
1042
+ storage: {
1043
+ value: content,
1044
+ representation: 'storage',
1045
+ },
1046
+ },
1047
+ });
1048
+ created.push(page);
1049
+
1050
+ // Rate limit protection: wait between requests
1051
+ await new Promise(resolve => setTimeout(resolve, 200));
1052
+ }
1053
+
1054
+ return created;
1055
+ }
1056
+ ```
1057
+
1058
+ ### Batch Update Pages
1059
+
1060
+ ```ts
1061
+ async function updateMultiplePages(
1062
+ updates: Array<{ id: string; title?: string; content: string }>
1063
+ ) {
1064
+ const results = [];
1065
+
1066
+ for (const { id, title, content } of updates) {
1067
+ const current = await client.content.getContent({
1068
+ id,
1069
+ expand: ['version', 'space'],
1070
+ });
1071
+
1072
+ const updated = await client.content.updateContent({
1073
+ id,
1074
+ type: 'page',
1075
+ title: title || current.title,
1076
+ space: { key: current.space?.key },
1077
+ version: {
1078
+ number: current.version!.number! + 1,
1079
+ },
1080
+ body: {
1081
+ storage: {
1082
+ value: content,
1083
+ representation: 'storage',
1084
+ },
1085
+ },
1086
+ });
1087
+
1088
+ results.push(updated);
1089
+ await new Promise(resolve => setTimeout(resolve, 200));
1090
+ }
1091
+
1092
+ return results;
1093
+ }
1094
+ ```
1095
+
1096
+ ## Performance and Optimization
1097
+
1098
+ ### Use Expand Wisely
1099
+
1100
+ Only expand fields you need to reduce response size:
1101
+
1102
+ ```ts
1103
+ // Bad - expands everything
1104
+ const page = await client.content.getContent({
1105
+ id: '123456789',
1106
+ expand: ['body.storage', 'body.view', 'body.editor', 'version', 'space', 'history', 'ancestors', 'descendants', 'container'],
1107
+ });
1108
+
1109
+ // Good - only what you need
1110
+ const page = await client.content.getContent({
1111
+ id: '123456789',
1112
+ expand: ['body.storage', 'version'],
1113
+ });
1114
+ ```
1115
+
1116
+ ### Pagination Best Practices
1117
+
1118
+ ```ts
1119
+ async function getAllPagesInSpace(spaceKey: string) {
1120
+ const allPages = [];
1121
+ let start = 0;
1122
+ const limit = 100; // Max recommended: 100
1123
+
1124
+ while (true) {
1125
+ const response = await client.content.getContent({
1126
+ spaceKey,
1127
+ type: 'page',
1128
+ start,
1129
+ limit,
1130
+ });
1131
+
1132
+ if (!response.results || response.results.length === 0) {
1133
+ break;
1134
+ }
1135
+
1136
+ allPages.push(...response.results);
1137
+
1138
+ if (response.results.length < limit) {
1139
+ break;
1140
+ }
1141
+
1142
+ start += limit;
1143
+ }
1144
+
1145
+ return allPages;
1146
+ }
1147
+ ```
1148
+
1149
+ ### Caching Strategies
1150
+
1151
+ ```ts
1152
+ class ConfluenceCache {
1153
+ private cache = new Map<string, { data: any; expires: number }>();
1154
+
1155
+ constructor(private client: ConfluenceClient, private ttlMs = 60000) {}
1156
+
1157
+ async getPage(id: string) {
1158
+ const cached = this.cache.get(id);
1159
+
1160
+ if (cached && Date.now() < cached.expires) {
1161
+ return cached.data;
1162
+ }
1163
+
1164
+ const page = await this.client.content.getContent({ id });
1165
+
1166
+ this.cache.set(id, {
1167
+ data: page,
1168
+ expires: Date.now() + this.ttlMs,
1169
+ });
1170
+
1171
+ return page;
1172
+ }
1173
+
1174
+ invalidate(id: string) {
1175
+ this.cache.delete(id);
1176
+ }
1177
+ }
1178
+ ```
1179
+
1180
+ ## TypeScript Support
1181
+
1182
+ ### Typed Responses
1183
+
1184
+ ```ts
1185
+ import { Content, Space, User } from 'confluence.js/out/api/models';
1186
+
1187
+ const page: Content = await client.content.getContent({ id: '123456789' });
1188
+ const space: Space = await client.space.getSpace({ spaceKey: 'DEMO' });
1189
+ const user: User = await client.user.getCurrentUser();
1190
+ ```
1191
+
1192
+ ### Type-Safe Page Creation
1193
+
1194
+ ```ts
1195
+ import { ContentCreate } from 'confluence.js/out/api/models';
1196
+
1197
+ const pageData: ContentCreate = {
1198
+ type: 'page',
1199
+ title: 'Type-Safe Page',
1200
+ space: { key: 'DEMO' },
1201
+ body: {
1202
+ storage: {
1203
+ value: '<p>Content</p>',
1204
+ representation: 'storage',
1205
+ },
1206
+ },
1207
+ };
1208
+
1209
+ const created = await client.content.createContent(pageData);
1210
+ ```
1211
+
1212
+ ## Common Patterns
1213
+
1214
+ ### Create or Update Page
1215
+
1216
+ ```ts
1217
+ async function createOrUpdatePage(
1218
+ spaceKey: string,
1219
+ title: string,
1220
+ content: string
1221
+ ) {
1222
+ // Try to find existing page
1223
+ const searchResult = await client.content.getContent({
1224
+ spaceKey,
1225
+ title,
1226
+ expand: ['version', 'space'],
1227
+ });
1228
+
1229
+ if (searchResult.results && searchResult.results.length > 0) {
1230
+ // Update existing
1231
+ const existing = searchResult.results[0];
1232
+ return await client.content.updateContent({
1233
+ id: existing.id!,
1234
+ type: 'page',
1235
+ title,
1236
+ space: { key: spaceKey },
1237
+ version: {
1238
+ number: existing.version!.number! + 1,
1239
+ },
1240
+ body: {
1241
+ storage: {
1242
+ value: content,
1243
+ representation: 'storage',
1244
+ },
1245
+ },
1246
+ });
1247
+ } else {
1248
+ // Create new
1249
+ return await client.content.createContent({
1250
+ type: 'page',
1251
+ title,
1252
+ space: { key: spaceKey },
1253
+ body: {
1254
+ storage: {
1255
+ value: content,
1256
+ representation: 'storage',
1257
+ },
1258
+ },
1259
+ });
1260
+ }
1261
+ }
1262
+ ```
1263
+
1264
+ ### Build Table of Contents
1265
+
1266
+ ```ts
1267
+ async function buildTableOfContents(spaceKey: string) {
1268
+ const pages = await client.content.getContent({
1269
+ spaceKey,
1270
+ type: 'page',
1271
+ limit: 100,
1272
+ });
1273
+
1274
+ let tocHtml = '<h2>Table of Contents</h2><ul>';
1275
+
1276
+ for (const page of pages.results || []) {
1277
+ tocHtml += `<li><ac:link><ri:page ri:content-title="${page.title}"/></ac:link></li>`;
1278
+ }
1279
+
1280
+ tocHtml += '</ul>';
1281
+
1282
+ return tocHtml;
1283
+ }
1284
+ ```
1285
+
1286
+ ### Export Page to Different Format
1287
+
1288
+ ```ts
1289
+ async function exportPageAsPDF(pageId: string) {
1290
+ const page = await client.content.getContent({
1291
+ id: pageId,
1292
+ expand: ['body.export_view'],
1293
+ });
1294
+
1295
+ // Export view provides HTML optimized for export
1296
+ return page.body?.export_view?.value;
1297
+ }
1298
+ ```
1299
+
1300
+ ## Content Body Formats
1301
+
1302
+ Confluence supports multiple body representations:
1303
+
1304
+ - `storage`: XHTML format used for storage (required for create/update)
1305
+ - `view`: HTML for rendering in browser
1306
+ - `export_view`: HTML optimized for export
1307
+ - `editor`: Format used in the editor
1308
+ - `anonymous_export_view`: HTML for anonymous viewing
1309
+
1310
+ ```ts
1311
+ const page = await client.content.getContent({
1312
+ id: '123456789',
1313
+ expand: ['body.storage', 'body.view', 'body.export_view'],
1314
+ });
1315
+
1316
+ console.log('Storage format:', page.body?.storage?.value);
1317
+ console.log('View format:', page.body?.view?.value);
1318
+ console.log('Export format:', page.body?.export_view?.value);
1319
+ ```
1320
+
1321
+ ## Common Mistakes to Avoid
1322
+
1323
+ - **Not incrementing version number** when updating content (causes 409 conflict)
1324
+ - **Forgetting to expand fields** needed in response (results in undefined properties)
1325
+ - **Using wrong representation** for body content (use 'storage' for create/update)
1326
+ - **Not handling pagination** when fetching multiple items (misses items beyond first page)
1327
+ - **Hardcoding credentials** instead of using environment variables (security risk)
1328
+ - **Not handling rate limits** in bulk operations (causes 429 errors)
1329
+ - **Creating pages without checking if they exist** (creates duplicates)
1330
+ - **Not URL-encoding** special characters in space keys or titles
1331
+ - **Assuming synchronous operations** (all API calls are async and return promises)
1332
+ - **Not catching errors** properly (unhandled rejections crash Node.js apps)
1333
+ - **Using outdated packages** like confluence-api instead of confluence.js
1334
+ - **Forgetting authentication object** in ConfluenceClient initialization
1335
+ - **Not escaping HTML** in content values (causes malformed XML in storage format)
1336
+
1337
+ ## Reference Links
1338
+
1339
+ - **confluence.js Documentation**: https://mrrefactoring.github.io/confluence.js/
1340
+ - **Confluence Cloud REST API v2**: https://developer.atlassian.com/cloud/confluence/rest/v2/
1341
+ - **Confluence Cloud REST API v1**: https://developer.atlassian.com/cloud/confluence/rest/v1/
1342
+ - **CQL (Confluence Query Language)**: https://developer.atlassian.com/cloud/confluence/advanced-searching-using-cql/
1343
+ - **Storage Format Guide**: https://confluence.atlassian.com/doc/confluence-storage-format-790796544.html
1344
+ - **Atlassian API Tokens**: https://id.atlassian.com/manage-profile/security/api-tokens
1345
+ - **Rate Limits**: https://developer.atlassian.com/cloud/confluence/rate-limiting/
1346
+ - **OAuth 2.0 (3LO)**: https://developer.atlassian.com/cloud/confluence/oauth-2-3lo-apps/
1347
+ - **Atlassian Connect (JWT)**: https://developer.atlassian.com/cloud/confluence/authentication-for-apps/