@codybrom/denim
v1.3.6
Published
Typescript/Deno module to simplify posting to Threads
Downloads
15
Readme
Denim
Denim is a Deno module that provides a simple interface for posting single Threads posts using text, images, or videos.
Features
- Create and publish posts on Threads with an easy-use-API
- Supports text-only, image, video, and carousel posts
- Add alt text to image and video posts
- Attach links to text posts
- Geo-gate content to specific countries
- Control who can reply to posts
- Retrieve publishing rate limit information
- Ready to deploy as an edge function
Installation
Using with Deno
To add Denim to your Deno project, you can use the following command:
deno add @codybrom/denim
This will add the latest version of Denim to your project's dependencies.
Usage
To import straight from JSR:
import { ThreadsPostRequest, createThreadsContainer, publishThreadsContainer } from 'jsr:@codybrom/denim';
Basic Usage
import { createThreadsContainer, publishThreadsContainer, ThreadsPostRequest } from "jsr:@codybrom/denim";
const request: ThreadsPostRequest = {
userId: "YOUR_USER_ID",
accessToken: "YOUR_ACCESS_TOKEN",
mediaType: "TEXT",
text: "Check out Denim on GitHub!",
linkAttachment: "https://github.com/codybrom/denim",
replyControl: "everyone",
};
// Create a container
const containerId = await createThreadsContainer(request);
// Publish the container
const publishedId = await publishThreadsContainer(request.userId, request.accessToken, containerId);
console.log(`Post published with ID: ${publishedId}`);
Retrieving Publishing Rate Limit
import { getPublishingLimit } from "jsr:@codybrom/denim";
const userId = "YOUR_USER_ID";
const accessToken = "YOUR_ACCESS_TOKEN";
try {
const rateLimit = await getPublishingLimit(userId, accessToken);
console.log("Current usage:", rateLimit.quota_usage);
console.log("Total quota:", rateLimit.config.quota_total);
console.log("Quota duration (seconds):", rateLimit.config.quota_duration);
} catch (error) {
console.error("Failed to retrieve rate limit information:", error);
}
Posting Different Media Types
Text-only Post
const textRequest: ThreadsPostRequest = {
userId: "YOUR_USER_ID",
accessToken: "YOUR_ACCESS_TOKEN",
mediaType: "TEXT",
text: "This is a text-only post on Threads!",
};
Text Post with Link Attachment
const textRequest: ThreadsPostRequest = {
userId: "YOUR_USER_ID",
accessToken: "YOUR_ACCESS_TOKEN",
mediaType: "TEXT",
text: "This is a post with an attached link on Threads!",
linkAttachment: "https://example.com",
};
Image Post with Alt Text
const imageRequest: ThreadsPostRequest = {
userId: "YOUR_USER_ID",
accessToken: "YOUR_ACCESS_TOKEN",
mediaType: "IMAGE",
text: "Check out this image!",
imageUrl: "https://example.com/image.jpg",
altText: "A beautiful sunset over the ocean",
};
Video Post
const videoRequest: ThreadsPostRequest = {
userId: "YOUR_USER_ID",
accessToken: "YOUR_ACCESS_TOKEN",
mediaType: "VIDEO",
text: "Watch this video!",
videoUrl: "https://example.com/video.mp4",
};
Video Post with Alt Text, Reply Control and Geo-gating* (requires special account permission)
const videoRequest: ThreadsPostRequest = {
userId: "YOUR_USER_ID",
accessToken: "YOUR_ACCESS_TOKEN",
mediaType: "VIDEO",
text: "Watch this video!",
videoUrl: "https://example.com/video.mp4",
altText: "A tutorial on how to make a chocolate cake",
allowlistedCountryCodes: ["US", "GB"],
replyControl: "mentioned_only",
};
Carousel Post
import { createCarouselItem, createThreadsContainer, publishThreadsContainer, ThreadsPostRequest } from "jsr:@codybrom/denim";
// First, create carousel items
const item1Id = await createCarouselItem({
userId: "YOUR_USER_ID",
accessToken: "YOUR_ACCESS_TOKEN",
mediaType: "IMAGE",
imageUrl: "https://example.com/image1.jpg",
altText: "First image in the carousel",
});
const item2Id = await createCarouselItem({
userId: "YOUR_USER_ID",
accessToken: "YOUR_ACCESS_TOKEN",
mediaType: "VIDEO",
videoUrl: "https://example.com/video.mp4",
altText: "Video in the carousel",
});
// Then, create the carousel post
const carouselRequest: ThreadsPostRequest = {
userId: "YOUR_USER_ID",
accessToken: "YOUR_ACCESS_TOKEN",
mediaType: "CAROUSEL",
text: "Check out this carousel post!",
children: [item1Id, item2Id],
replyControl: "everyone",
};
const containerId = await createThreadsContainer(carouselRequest);
const publishedId = await publishThreadsContainer(carouselRequest.userId, carouselRequest.accessToken, containerId);
console.log(`Carousel post published with ID: ${publishedId}`);
Deploying as an Edge Function
Denim can be easily deployed as an edge function. An example implementation is provided in examples/edge-function.ts
.
To deploy:
- Copy the
examples/edge-function.ts
file to your project. - Deploy this file to your serverless platform that supports Deno.
- Send POST requests to your function's URI with the appropriate JSON body.
Example cURL Commands
# Post a text-only Thread
curl -X POST <YOUR_FUNCTION_URI> \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_AUTH_KEY" \
-d '{
"userId": "YOUR_USER_ID",
"accessToken": "YOUR_ACCESS_TOKEN",
"mediaType": "TEXT",
"text": "Hello from Denim!"
}'
# Post an image Thread
curl -X POST <YOUR_FUNCTION_URI> \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_AUTH_KEY" \
-d '{
"userId": "YOUR_USER_ID",
"accessToken": "YOUR_ACCESS_TOKEN",
"mediaType": "IMAGE",
"text": "Check out this image I posted with Denim!",
"imageUrl": "https://example.com/image.jpg"
}'
# Post a video Thread
curl -X POST <YOUR_FUNCTION_URI> \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_AUTH_KEY" \
-d '{
"userId": "YOUR_USER_ID",
"accessToken": "YOUR_ACCESS_TOKEN",
"mediaType": "VIDEO",
"text": "Watch this video I posted with Denim!",
"videoUrl": "https://example.com/video.mp4"
}'
Note: Replace with your actual authorization headers if your edge function requires them (or remove them).
Security Note
Ensure that your function is deployed with appropriate access controls and authentication mechanisms to protect sensitive data like access tokens.
Testing
To run the tests:
deno test mod_test.ts
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.