{"id":15023010,"url":"https://github.com/lostfictions/twoot","last_synced_at":"2026-01-19T09:34:57.827Z","repository":{"id":57383003,"uuid":"115255471","full_name":"lostfictions/twoot","owner":"lostfictions","description":"tweet and/or toot with ease.","archived":false,"fork":false,"pushed_at":"2023-01-14T02:19:40.000Z","size":445,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-04-18T07:02:00.254Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lostfictions.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-12-24T10:23:15.000Z","updated_at":"2022-05-03T20:59:09.000Z","dependencies_parsed_at":"2023-02-09T18:45:44.516Z","dependency_job_id":null,"html_url":"https://github.com/lostfictions/twoot","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lostfictions%2Ftwoot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lostfictions%2Ftwoot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lostfictions%2Ftwoot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lostfictions%2Ftwoot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lostfictions","download_url":"https://codeload.github.com/lostfictions/twoot/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247415930,"owners_count":20935385,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-09-24T19:58:38.102Z","updated_at":"2026-01-19T09:34:57.821Z","avatar_url":"https://github.com/lostfictions.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# twoot\n\n\u003ca href=\"https://www.npmjs.com/package/twoot\"\u003e\n\u003cimg src=\"https://img.shields.io/npm/v/twoot.svg?logo=npm\" alt=\"NPM version\" /\u003e\n\u003c/a\u003e\n\ntoot and/or ~~tweet~~ skeet. a common (and lowest-common-denominator) api for simplifying cross-posting to mastodon and ~~twitter~~ bsky.\n\n\u003e [!WARNING]\n\u003e note that this library is primarily intended for my own personal hobbyist use with [my bots](https://github.com/lostfictions?tab=repositories\u0026q=botally). i can only provide limited support for other use cases on a best-effort basis.\n\n![noot and/or twoot](pingu.gif)\n\n## install\n\n```sh\nnpm install twoot\n# OR\nyarn add twoot\n# OR\npnpm i twoot\n```\n\n## usage\n\n```ts\nimport { twoot } from \"twoot\";\n\nvoid (async () =\u003e {\n  const results = await twoot(\n    {\n      status: \"testing a twoot\",\n\n      // upload a file from disk with with the `path` param, or pass an image\n      // buffer directly with the `buffer` param.\n      media: [{ path: \"pingu.gif\" }],\n\n      // some properties unique to a single service, like per-post visibility\n      // for mastodon, are supported.\n      visibility: \"unlisted\",\n    },\n\n    // pass a single service configuration object, or pass an array of them to\n    // post to multiple services at once.\n    [\n      {\n        type: \"mastodon\",\n        server: process.env.MASTODON_SERVER,\n        token: process.env.MASTODON_TOKEN,\n      },\n      {\n        type: \"bsky\",\n        username: process.env.BSKY_USERNAME,\n        password: process.env.BSKY_PASSWORD,\n      },\n    ],\n  );\n\n  await twoot(\n    // if you pass in an array of statuses, they'll be posted as a thread.\n    [{ status: \"one\" }, { status: \"two\" }, { status: \"three\" }],\n    {\n      type: \"mastodon\",\n      server: process.env.MASTODON_SERVER,\n      token: process.env.MASTODON_TOKEN,\n    },\n    // by default `twoot` will throw if posting to *all* services fails, but you\n    // can configure it to throw if posting to *any* service fails.\n    { rejectOnAnyFailure: true },\n  );\n\n  // the return value is an array of results of attempting to post to each\n  // provided service. they're returned in the same order you passed them\n  // in.\n  for (const res of results) {\n    if (res.type === \"error\") {\n      // if `rejectOnAnyFailure` isn't set to `true`, the return value may\n      // contain failures. you're responsible for checking for them and\n      // deciding how to handle them.\n      console.error(`error while twooting:\\n${res.message}\\n`);\n    } else if (res.type === \"bsky\") {\n      console.log(`skeeted at '${res.status.uri}'!`);\n    } else {\n      console.log(`tooted at '${res.status.url}'!`);\n    }\n  }\n})();\n```\n\n###### [more bots?](https://github.com/lostfictions?tab=repositories\u0026q=botally)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flostfictions%2Ftwoot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flostfictions%2Ftwoot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flostfictions%2Ftwoot/lists"}