{"id":15567378,"url":"https://github.com/maxzaleski/usesendcode","last_synced_at":"2025-10-05T00:06:09.036Z","repository":{"id":65174015,"uuid":"573201174","full_name":"maxzaleski/useSendCode","owner":"maxzaleski","description":"A React (NextJS-oriented) hook that facilitates operations such as sending one-time codes.","archived":false,"fork":false,"pushed_at":"2023-07-11T19:10:53.000Z","size":230,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-24T13:32:36.476Z","etag":null,"topics":["account-recovery","nextjs","one-time-code","react"],"latest_commit_sha":null,"homepage":"","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/maxzaleski.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-12-01T23:11:34.000Z","updated_at":"2023-01-05T11:36:11.000Z","dependencies_parsed_at":"2024-12-09T04:41:37.498Z","dependency_job_id":"d6575944-9478-4c3d-be16-66b34ded9b9f","html_url":"https://github.com/maxzaleski/useSendCode","commit_stats":{"total_commits":9,"total_committers":3,"mean_commits":3.0,"dds":0.2222222222222222,"last_synced_commit":"3f3edc9eb60e6fb3c1de5e5c53423dd715da381a"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/maxzaleski/useSendCode","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxzaleski%2FuseSendCode","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxzaleski%2FuseSendCode/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxzaleski%2FuseSendCode/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxzaleski%2FuseSendCode/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maxzaleski","download_url":"https://codeload.github.com/maxzaleski/useSendCode/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxzaleski%2FuseSendCode/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278391220,"owners_count":25978947,"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-10-04T02:00:05.491Z","response_time":63,"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":["account-recovery","nextjs","one-time-code","react"],"created_at":"2024-10-02T17:10:55.898Z","updated_at":"2025-10-05T00:06:09.021Z","avatar_url":"https://github.com/maxzaleski.png","language":"TypeScript","readme":"# useSendCode\n\nA React (NextJS-oriented) hook that facilitates operations such as sending one-time codes.\n\n## Table of Contents\n\n- [useSendCode](#usesendcode)\n  - [Table of Contents](#table-of-contents)\n  - [Features](#features)\n  - [Motivation](#motivation)\n    - [Caveat](#caveat)\n  - [Installation](#installation)\n  - [Usage](#usage)\n    - [Configuration](#configuration)\n    - [Properties](#properties)\n  - [Understanding the hook's behaviour](#understanding-the-hooks-behaviour)\n    - [When a user clicks on the CTA](#when-a-user-clicks-on-the-cta)\n    - [When the cooldown is active, but the user refreshes the page](#when-the-cooldown-is-active-but-the-user-refreshes-the-page)\n    - [When the cooldown period is over](#when-the-cooldown-period-is-over)\n  - [TypeScript Support](#typescript-support)\n  - [License](#license)\n\n---\n\n## Features\n\n- Handle spam-sensitive operations such as one-time codes\n- Session tracking through server-only cookie\n- Session recovery on reload\n- Component (button) props that handle every aspect of the user-facing CTA (label, disabled, loading, etc)\n\n## Motivation\n\nLow-cost solution to spam-sensitive operations. This solution omits the use of a cache which might not always be available in early-stage applications.\n\n### Caveat\n\nThis solution was designed around the ability to retrieve server-only cookies with relative ease, e.g. NextJS' `getServerSideProps`. A vanilla React application would not be suitable for this solution.\n\n## Installation\n\nInstall through your package manager of choice (npm, yarn, etc)\n\n```\nnpm -i @mzaleski/use-send-code\n```\n\n```\nyarn add @mzaleski/use-send-code\n```\n\n## Usage\n\nExample usage with NextJS' `getServerSideProps`:\n\n```tsx\nimport { useSendCode } from '@mzaleski/use-send-code';\nimport { Button } from 'src/components';\n\nasync function worker(iamIdentifier: string): Promise\u003cvoid\u003e { ... }\n\nfunction AccountRecoveryPage({ cookiePayload }) {\n  const { sendCode, status, buttonProps } = useSendCode(worker, {\n    iamIdentifier: 'some-id',\n    lastCodeIdentifier: cookiePayload?.iamIdentifier,\n    lastCodeSendAt: cookiePayload?.sentAt,\n    callOnMount: true,\n    cooldownPeriod: 2 * 60,\n    buttonPropsActiveLabel: 'Recover my account',\n    buttonPropsLoadingPropName: 'isLoading',\n    debugStatements: process.env.NODE_ENV === 'development',\n    sessionClearHandler: async () =\u003e { ... },\n    sessionPersistHandler: async (iamIdentifier) =\u003e { ... },\n  });\n\n  const sendRecoveryCode = async () =\u003e {\n    const err = await sendCode();\n    if (err) {\n      // handle error\n    }\n  };\n\n  return (\n    \u003cButton {...buttonProps} onClick={sendRecoveryCode} /\u003e\n  );\n}\n\nexport async function getServerSideProps(context) {\n  /** retrieve server-only cookie and deserialise it */\n  const cookiePayload = {...};\n\n  return {\n    props: {\n      cookiePayload,\n    },\n  };\n}\n```\n\n### Configuration\n\nThe hook's configuration is done through the `opts` object which has the following properties:\n\n| Name | Type | Description | Default |\n| --- | --- | --- | --- |\niamIdentifier | String | The current user's unique identifier | [required] |\nsessionClearHandler | Function | A function responsible for clearing the server-only cookie | [required] |\nsessionPersistHandler | Function | - A function responsible for creating the server-only cookie; it is given the `iamIdentifier` as parameter - The signature encourages the return of a server timestamp | [required] |\nlastCodeIdentifier? | String | [retrieved from server-only cookie] the last code's `iamIdentifier` | `undefined` |\nlastCodeSendAt? | String, Number | [retrieved from server-only cookie] when the last code was sent; it will be parsed by the Javascript `Date` class. If the input is unparsable, the hook will throw `InvalidLastCodeSentAtError` | `undefined` |\ncallOnMount? | Boolean | Whether to call the worker on component mount | `false` |\ncooldownPeriod? | Number | The cooldown period in seconds | `300` (5 minutes) |\nbuttonPropsActiveLabel? | String | The button's label when a new code is available | `\"Send me a new code\"` |\nbuttonPropsLoadingPropName? | String | [Custom component support] specify the `loading` boolean property name on a custom button component | `\"loading\"` |\ndebugStatements? | Boolean | Whether to log debug statements (requires development mode) | `false` |\n\n### Properties\n\nThe hook returns an object with the following properties:\n\n| Name | Type | Description |\n| --- | --- | --- |\nsendCode | Function | The function responsible for calling the worker and updating the internal state |\nreset | Function | Will reset the hook to a `\"READY\"` state; this same function is called once the cooldown has expired |\nstatus | String | The current status of the hook; it can be one of the following: `\"READY\"`, `\"COOLDOWN\"`, `\"SENDING\"`, `\"RESTORING\"` |\nbuttonProps | Object | The props that should be passed to the button component; affected by `buttonPropsActiveLabel`, `buttonPropsLoadingPropName` |\n\n## Understanding the hook's behaviour \n\n### When a user clicks on the CTA\n\nThe hook will...\n\n1. Call your worker and perform the operation\n2. Call `sessionPersistHandler` with the given `iamIdentifier` to create a server-only cookie\n3. Update its internal state as well the button's props in order to reflect the change \n\n### When the cooldown is active, but the user refreshes the page\n\nThe hook will restore the previous state by looking at `lastCodeIdentifier` and `lastCodeSendAt` from the server-only cookie.\n   \n### When the cooldown period is over\n\nThe hook will...\n\n1. Call `sessionClearHandler` to clear the server-only cookie\n2. Update its internal state as well the button's props in order to reflect the change\n\n## TypeScript Support \n\nYou will find a collection of typings bundled with the package.\n\n## License\n\n[MIT License](LICENSE) (c) 2022 Maximilien Zaleski\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxzaleski%2Fusesendcode","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaxzaleski%2Fusesendcode","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxzaleski%2Fusesendcode/lists"}