{"id":28454408,"url":"https://github.com/tinyplex/tinytick","last_synced_at":"2025-08-17T20:11:08.172Z","repository":{"id":280746030,"uuid":"914540424","full_name":"tinyplex/tinytick","owner":"tinyplex","description":"An easy way to orchestrate JavaScript tasks.","archived":false,"fork":false,"pushed_at":"2025-06-10T20:16:10.000Z","size":1639,"stargazers_count":45,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-07-28T12:51:21.328Z","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":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tinyplex.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"jamesgpearce"}},"created_at":"2025-01-09T19:51:00.000Z","updated_at":"2025-07-21T17:45:33.000Z","dependencies_parsed_at":"2025-04-15T01:22:39.335Z","dependency_job_id":"2289057e-7673-4df5-9ba6-d391e94b70f9","html_url":"https://github.com/tinyplex/tinytick","commit_stats":null,"previous_names":["tinyplex/tinytick"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/tinyplex/tinytick","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinyplex%2Ftinytick","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinyplex%2Ftinytick/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinyplex%2Ftinytick/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinyplex%2Ftinytick/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tinyplex","download_url":"https://codeload.github.com/tinyplex/tinytick/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinyplex%2Ftinytick/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270899582,"owners_count":24664720,"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","status":"online","status_checked_at":"2025-08-17T02:00:09.016Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":"2025-06-06T19:13:46.154Z","updated_at":"2025-08-17T20:11:08.164Z","avatar_url":"https://github.com/tinyplex.png","language":"TypeScript","readme":"\u003clink rel=\"preload\" as=\"image\" href=\"https://tinybase.org/favicon.svg?asImg\"\u003e\u003clink rel=\"preload\" as=\"image\" href=\"https://tinywidgets.org/favicon.svg?asImg\"\u003e\u003clink rel=\"preload\" as=\"image\" href=\"https://tinytick.org/favicon.svg?asImg\"\u003e\u003csection id=\"hero\"\u003e\u003ch2 id=\"a-tiny-but-very-useful-javascript-task-orchestrator\"\u003eA tiny but very useful JavaScript task orchestrator.\u003c/h2\u003e\u003c/section\u003e\u003cp\u003e\u003ca href=\"https://tinytick.org/guides/releases/#v1-2\"\u003e\u003cem\u003eNEW!\u003c/em\u003e v1.2 release\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003cspan id=\"one-with\"\u003eThe one with reactivity - and React!\u003c/span\u003e\u003c/p\u003e\u003cp\u003e\u003ca class=\"start\" href=\"https://tinytick.org/guides/getting-started/\"\u003eGet started\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://tinytick.org/demos/\"\u003eTry the demos\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://tinytick.org/api/tinytick/interfaces/manager/manager/\"\u003eRead the docs\u003c/a\u003e\u003c/p\u003e\u003chr\u003e\u003csection\u003e\u003ch2 id=\"task-management-is-hard\"\u003e\u003ca href=\"https://tinytick.org/api/tinytick/type-aliases/task/task/\"\u003e\u003ccode\u003eTask\u003c/code\u003e\u003c/a\u003e management is hard.\u003c/h2\u003e\u003cp\u003eBackground tasks like fetching, syncing, and cache eviction are common in intelligent web applications. Yet managing them - with scheduling, failure handling, retries, and so on - can be a pain.\u003c/p\u003e\u003c/section\u003e\u003csection\u003e\u003ch2 id=\"so-make-it-easy\"\u003eSo make it easy.\u003c/h2\u003e\u003cp\u003eSpecify your tasks imperatively, ahead of time, and then configure their schedules, timeouts, and retry sequences - and let TinyTick take care of everything for you. Oh and it\u0026#x27;s only \u003cem\u003e2.8kB\u003c/em\u003e.\u003c/p\u003e\u003c/section\u003e\u003chr\u003e\u003csection\u003e\u003ch2 id=\"create-and-start-a-manager-object\"\u003eCreate and start a \u003ca href=\"https://tinytick.org/api/tinytick/interfaces/manager/manager/\"\u003e\u003ccode\u003eManager\u003c/code\u003e\u003c/a\u003e object.\u003c/h2\u003e\u003cp\u003eThis is the main entry point for the TinyTick API.\u003c/p\u003e\u003c/section\u003e\n\n```js\nimport {createManager} from 'tinytick';\nconst manager = createManager().start();\n```\n\n\u003csection\u003e\u003ch2 id=\"register-a-task\"\u003eRegister a \u003ca href=\"https://tinytick.org/api/tinytick/type-aliases/task/task/\"\u003e\u003ccode\u003eTask\u003c/code\u003e\u003c/a\u003e.\u003c/h2\u003e\u003cp\u003eA TinyTick task is simply an asynchronous function that can take an optional string argument (and a few other things, as you\u0026#x27;ll see later!). Simply register it with a string \u003ca href=\"https://tinytick.org/api/tinytick/type-aliases/identity/id/\"\u003e\u003ccode\u003eId\u003c/code\u003e\u003c/a\u003e.\u003c/p\u003e\u003c/section\u003e\n\n```js\nconst ping = async (url) =\u003e await fetch(url);\nmanager.setTask('ping', ping);\n```\n\n\u003csection\u003e\u003ch2 id=\"schedule-it-to-run\"\u003eSchedule it to run.\u003c/h2\u003e\u003cp\u003eBy default, TinyTask schedules the task to start as soon as possible. And it will generate a unique \u003ca href=\"https://tinytick.org/api/tinytick/type-aliases/identity/id/\"\u003e\u003ccode\u003eId\u003c/code\u003e\u003c/a\u003e for each \u0026#x27;task run\u0026#x27; so you can track its progress.\u003c/p\u003e\u003c/section\u003e\n\n```js\nconst taskRunId = manager.scheduleTaskRun(\n  'ping',\n  'https://example.com',\n);\n```\n\n\u003csection\u003e\u003ch2 id=\"keep-up-with-what-is-going-on\"\u003eKeep up with what is going on.\u003c/h2\u003e\u003cp\u003eThe \u003ca href=\"https://tinytick.org/api/tinytick/interfaces/manager/manager/\"\u003e\u003ccode\u003eManager\u003c/code\u003e\u003c/a\u003e object exposes plenty of accessors to let you inspect the tasks you have registered and the state of the task runs you\u0026#x27;ve scheduled.\u003c/p\u003e\u003c/section\u003e\n\n```js yolo\nconsole.log(manager.getTaskIds());\n// -\u003e ['ping']\nconsole.log(manager.getTaskRunInfo(taskRunId));\n// -\u003e {taskId: 'ping', arg: 'https://example.com', ...}\n```\n\n\u003csection\u003e\u003ch2 id=\"tinytick-is-reactive\"\u003eTinyTick is reactive.\u003c/h2\u003e\u003cp\u003eSubscribe to listeners that fire whenever critical things happen, like when a task starts, finishes, or fails. It uses the same API as TinyBase, so if you are familiar with listeners in that library, you\u0026#x27;ll feel right at home!\u003c/p\u003e\u003c/section\u003e\n\n```js\nconst listenerId1 = manager.addTaskRunRunningListener(\n  'ping',\n  null,\n  () =\u003e console.log('A ping started'),\n);\nconst listenerId2 = manager.addTaskRunFailedListener(\n  'ping',\n  null,\n  () =\u003e console.log('A ping failed'),\n);\n// ...\nmanager.delListener(listenerId1);\nmanager.delListener(listenerId2);\n```\n\n\u003csection\u003e\u003ch2 id=\"configure-timeouts-for-your-tasks\"\u003eConfigure timeouts for your tasks.\u003c/h2\u003e\u003cp\u003eTasks (or individual task runs) can have a timeout set, and they will be aborted if they run over. \u003ca href=\"https://tinytick.org/api/tinytick/type-aliases/task/task/\"\u003e\u003ccode\u003eTask\u003c/code\u003e\u003c/a\u003e functions are passed an \u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal\"\u003eAbortSignal\u003c/a\u003e parameter so you can handle the timeout. You can pass this straight on to the \u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/API/RequestInit\"\u003efetch\u003c/a\u003e call, for example.\u003c/p\u003e\u003c/section\u003e\n\n```js\nmanager.setTask(\n  'ping',\n  async (url, signal) =\u003e await fetch(url, {signal}),\n  undefined,\n  {maxDuration: 100}, // milliseconds\n);\n```\n\n\u003csection\u003e\u003ch2 id=\"orchestrate-retries\"\u003eOrchestrate retries.\u003c/h2\u003e\u003cp\u003eIf a task run fails (for taking too long, or throwing an exception), you can indicate that you want it to retry, and even configure a backoff strategy.\u003c/p\u003e\u003c/section\u003e\n\n```js\nmanager.setTask(\n  'ping',\n  async (url, signal) =\u003e await fetch(url, {signal}),\n  undefined, // we'll explain this argument in a moment!\n  {maxRetries: 3, retryDelay: '1000, 5000, 10000'},\n);\n```\n\n\u003csection\u003e\u003ch2 id=\"create-configuration-categories\"\u003eCreate configuration categories.\u003c/h2\u003e\u003cp\u003eA \u003ca href=\"https://tinytick.org/api/tinytick/type-aliases/task/task/\"\u003e\u003ccode\u003eTask\u003c/code\u003e\u003c/a\u003e can be assigned a category, which can have its own configuration for duration, retries, and retry delays. But of course, individual properties can still be overridden per task or per task run.\u003c/p\u003e\u003c/section\u003e\n\n```js\nmanager.setCategory('network', {\n  maxDuration: 100,\n  maxRetries: 3,\n  retryDelay: '1000, 5000, 10000',\n});\nmanager.setTask('ping', ping, 'network', {\n  maxRetries: 5,\n});\n```\n\n\u003csection\u003e\u003ch2 id=\"integrates-with-react\"\u003eIntegrates with React.\u003c/h2\u003e\u003cp\u003eThe optional \u003ca href=\"https://tinytick.org/api/ui-react/functions/context-components/provider/\"\u003e\u003ccode\u003eProvider\u003c/code\u003e\u003c/a\u003e component and a set of hooks in the \u003ca href=\"https://tinytick.org/api/ui-react/\"\u003e\u003ccode\u003eui-react\u003c/code\u003e\u003c/a\u003e module make it easy to integrate TinyTick into your React application so that you can start tasks or visualize their progress.\u003c/p\u003e\u003c/section\u003e\n\n```jsx yolo\nimport {\n  Provider,\n  useCreateManager,\n  useScheduleTaskRunCallback,\n  useSetTask,\n} from 'tinytick/ui-react';\n\nconst App = () =\u003e (\n  \u003cProvider manager={useCreateManager(createManager)}\u003e\n    \u003cPanel /\u003e\n  \u003c/Provider\u003e\n);\n\nconst Panel = () =\u003e {\n  useSetTask(\n    'ping',\n    async () =\u003e await fetch('https://example.org'),\n  );\n  return \u003cButton /\u003e;\n};\n\nconst Button = () =\u003e {\n  const callback = useScheduleTaskRunCallback('ping');\n  return \u003cbutton onClick={callback}\u003ePing\u003c/button\u003e;\n};\n```\n\n\u003csection\u003e\u003ch2 id=\"see-some-worked-examples\"\u003eSee some worked examples.\u003c/h2\u003e\u003cp\u003eWe are building up a set of \u003ca href=\"https://tinytick.org/guides/example-use-cases/\"\u003eExample Use Cases\u003c/a\u003e guides to show you how to use TinyTick in practice. If you\u0026#x27;re trying to access relational- or graph-like data over a network, for example, take a look at the \u003ca href=\"https://tinytick.org/guides/example-use-cases/paginated-and-nested-data/\"\u003ePaginated And Nested Data\u003c/a\u003e guide for a start!\u003c/p\u003e\u003c/section\u003e\n\n```js yolo\nmanager.scheduleTaskRun('fetchParents');\n// -\u003e 'Fetching https://api.org/parents?page=1'\n// -\u003e 'Storing parent A'\n// -\u003e 'Storing parent B'\n// -\u003e 'Fetching https://api.org/children?parentId=A\u0026page=1'\n// -\u003e 'Fetching https://api.org/children?parentId=B\u0026page=1'\n// -\u003e 'Fetching https://api.org/parents?page=2'\n```\n\n\u003csection\u003e\u003ch2 id=\"tiny-tested-and-documented\"\u003eTiny, tested, and documented.\u003c/h2\u003e\u003cp\u003eIf you chose to install TinyTick in your app, you\u0026#x27;ll only add a gzipped \u003cem\u003e2.8kB\u003c/em\u003e to your app. Life is easy when you have zero dependencies!\u003c/p\u003e\u003cp\u003eTinyBase has \u003cem\u003e100.0%\u003c/em\u003e test coverage, including the code throughout the documentation - even on this page. The guides, demos, and API examples are designed to make things as easy as possible.\u003c/p\u003e\u003c/section\u003e\u003cdiv class=\"table\"\u003e\u003ctable class=\"fixed\"\u003e\u003ctbody\u003e\u003ctr\u003e\u003cth width=\"30%\"\u003e \u003c/th\u003e\u003cth\u003eTotal\u003c/th\u003e\u003cth\u003eTested\u003c/th\u003e\u003cth\u003eCoverage\u003c/th\u003e\u003c/tr\u003e\u003ctr\u003e\u003cth class=\"right\"\u003eLines\u003c/th\u003e\u003ctd\u003e434\u003c/td\u003e\u003ctd\u003e434\u003c/td\u003e\u003ctd\u003e100.0%\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003cth class=\"right\"\u003eStatements\u003c/th\u003e\u003ctd\u003e487\u003c/td\u003e\u003ctd\u003e487\u003c/td\u003e\u003ctd\u003e100.0%\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003cth class=\"right\"\u003eFunctions\u003c/th\u003e\u003ctd\u003e190\u003c/td\u003e\u003ctd\u003e190\u003c/td\u003e\u003ctd\u003e100.0%\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003cth class=\"right\"\u003eBranches\u003c/th\u003e\u003ctd\u003e175\u003c/td\u003e\u003ctd\u003e175\u003c/td\u003e\u003ctd\u003e100.0%\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003cth class=\"right\"\u003eTests\u003c/th\u003e\u003ctd colspan=\"3\"\u003e187\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003cth class=\"right\"\u003eAssertions\u003c/th\u003e\u003ctd colspan=\"3\"\u003e677\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003c/div\u003e\u003chr\u003e\u003cp\u003e\u003ca class=\"start\" href=\"https://tinytick.org/guides/getting-started/\"\u003eGet started\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://tinytick.org/demos/\"\u003eTry the demos\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://tinytick.org/api/tinytick/interfaces/manager/manager/\"\u003eRead the docs\u003c/a\u003e\u003c/p\u003e\u003chr\u003e\u003csection id=\"family\"\u003e\u003ch2 id=\"meet-the-family\"\u003eMeet the family\u003c/h2\u003e\u003cp\u003eTinyTick is part of a group of small libraries designed to help make rich client and local-first apps easier to build. Check out the others!\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://tinybase.org\" target=\"_blank\"\u003e\u003cimg src=\"https://tinybase.org/favicon.svg?asImg\" width=\"48\"\u003e\u003cbr\u003e\u003cb\u003eTinyBase\u003c/b\u003e\u003c/a\u003e\u003cbr\u003eA reactive data store and sync engine.\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://tinywidgets.org\" target=\"_blank\"\u003e\u003cimg src=\"https://tinywidgets.org/favicon.svg?asImg\" width=\"48\"\u003e\u003cbr\u003e\u003cb\u003eTinyWidgets\u003c/b\u003e\u003c/a\u003e\u003cbr\u003eA collection of tiny, reusable, UI components.\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://tinytick.org/favicon.svg?asImg\" width=\"48\"\u003e\u003cbr\u003e\u003cb\u003eTinyTick\u003c/b\u003e\u003cbr\u003eA tiny but very useful task orchestrator.\u003c/p\u003e\u003c/section\u003e","funding_links":["https://github.com/sponsors/jamesgpearce"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftinyplex%2Ftinytick","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftinyplex%2Ftinytick","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftinyplex%2Ftinytick/lists"}