{"id":19370306,"url":"https://github.com/codam-coding-college/fast42-ts","last_synced_at":"2025-04-23T15:32:12.734Z","repository":{"id":57943161,"uuid":"528912267","full_name":"codam-coding-college/Fast42-ts","owner":"codam-coding-college","description":"A super fast 42API connector written in typescript 🚀","archived":false,"fork":false,"pushed_at":"2024-07-24T15:16:23.000Z","size":1365,"stargazers_count":14,"open_issues_count":4,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-15T19:38:16.289Z","etag":null,"topics":["42api","42born2code","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/codam-coding-college.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":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-08-25T15:32:33.000Z","updated_at":"2025-02-28T07:48:24.000Z","dependencies_parsed_at":"2024-08-30T00:18:48.844Z","dependency_job_id":"d73a3b01-a612-44b2-99ab-cd9d4c25b729","html_url":"https://github.com/codam-coding-college/Fast42-ts","commit_stats":{"total_commits":76,"total_committers":3,"mean_commits":"25.333333333333332","dds":"0.21052631578947367","last_synced_commit":"6a8549cfea910683a096584a52491b4f2b7738e2"},"previous_names":["codam-coding-college/fast42"],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codam-coding-college%2FFast42-ts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codam-coding-college%2FFast42-ts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codam-coding-college%2FFast42-ts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codam-coding-college%2FFast42-ts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/codam-coding-college","download_url":"https://codeload.github.com/codam-coding-college/Fast42-ts/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250460564,"owners_count":21434265,"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":["42api","42born2code","typescript"],"created_at":"2024-11-10T08:14:56.825Z","updated_at":"2025-04-23T15:32:12.448Z","avatar_url":"https://github.com/codam-coding-college.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fast42\n\nFast TS/JS connector to the 42API, for server-side use.\n\nFeatures:\n- Fast! Gets the most out of your rate-limit, so you don't have to wait forever.\n- Automatically determines the rate limit of your API key.\n- Queues requests (using bottleneck)\n- Multi-key support (be carefull, it might be too fast! 🚀)\n- Convenience: fetch all pages from an endpoint with a single method call!\n- Clustering (v2.1 and up): using Redis you can run multiple instances on the same API keys!\n\nPublic Methods:\n```ts\nconstructor(\n  secrets: ApiSecret[] // Api Secrets, see type below\n  concurrentOffset?: number, // default is 0, can be used to slow down the requests. ex: if your key can do 4 req/s you can set this to 1 to only make 3 req/s. Usefull if your backend or db can't keep up.\n  jobExpiration?: number, // default is 20000ms, especially important when using redis to kill infinite jobs\n  redisConfig?: RedisConfig // config to connect to redis, see below\n);\n\ninterface ApiSecret {\n    client_id: string;\n    client_secret: string;\n}\ninterface RedisConfig {\n    host: string;\n    port: number;\n    password?: string;\n}\n\n// Always call .init() first after constructing Fast42!\ninit(): Promise\u003cFast42\u003e\n\ngetPage(url: string, page: string, options?: {\n    [key: string]: string;\n}): Promise\u003cResponse\u003e\n\ngetAllPages(url: string, options?: {\n    [key: string]: string;\n}, start?: number): Promise\u003cPromise\u003cResponse\u003e[]\u003e\n\nget(endpoint: string, options?: {\n    [key: string]: string;\n}): Promise\u003cResponse\u003e\n\ndelete(endpoint: string): Promise\u003cResponse\u003e\npost(endpoint: string, body: any): Promise\u003cResponse\u003e\npatch(endpoint: string, body: any): Promise\u003cResponse\u003e\nput(endpoint: string, body: any): Promise\u003cResponse\u003e\n\n// use a user's accesstoken to make the request, you still need to initialize Fast42 with the same api key used to authenticate the user\npostWithUserAccessToken(accessToken: AccessToken, endpoint: string, body: any): Promise\u003cResponse\u003e\n\n// used for testing, just runs a random job on the current limiter\ndoJob(job: any): Promise\u003cunknown\u003e;\n\n// Important when using redis! Closes the connection and stops logging.\ndisconnect(): Promise\u003cvoid[]\u003e;\n```\n\n### Install\n```sh\nnpm i @codam/fast42\n```\n\nBasic usage:\n\n```ts\nimport Fast42 from \"@codam/fast42\"\n\nconst api = await new Fast42([\n  {\n    client_id: \"\u003cYOUR API CLIENT ID\u003e\",\n    client_secret: \"\u003cYOUR API CLIENT SECRET\u003e\",\n  }\n]).init()\n\nconst campus_id = 14;\nconst pages = await api.getAllPages(`/campus/${campus_id}/users`, {\n  'filter[campus_id]': campus_id.toString(), // this makes no sense but it gives an example of using options\n})\n```\n\nObviously your id/secret should come from the environment and not be committed to git. (I recommend using a `.env` file and the `dotenv` package)\n\nHow I use it:\n\n```ts\nimport Fast42, { Response } from \"@codam/fast42\"\nimport dotenv from \"dotenv\";\n\n// utility function for error handling and logging\nfunction getPageNumberFromUrl(url: string): string | undefined {\n  const match = url.match(/page\\[number\\]=(\\d+)/);\n  if (match \u0026\u0026 match[1]) {\n    return match[1];\n  }\n  return undefined;\n}\n\n// utility function for logging errors\nfunction printHeaders(headers: any, print: (arg0: string) =\u003e void) {\n  headers.forEach((v: string, k: string) =\u003e {\n    print(`${k}: ${v}`)\n  })\n}\n\nasync function getAll42(\n  api: Fast42,\n  url: string,\n  options: { [key: string]: string },\n  callback: (_: Response) =\u003e any,\n) {\n  const pages: Promise\u003cPromise\u003cResponse\u003e[]\u003e = await api.getAllPages(url, options);\n\n  console.log(`Retrieving ${pages.length} pages for ${url}`);\n\n  // Attach a callback function to be called when the page promise resolves\n  return Promise.all(pages.map(async (page) =\u003e {\n    let p = await page;\n    const pagenr = getPageNumberFromUrl(p.url);\n    // retry when the ratelimit was hit\n    // (this can happen because the timing on 42api side is different from the timing of the Fast42 ratelimiter)\n    if (p.status === 429) {\n      if (pagenr) {\n        p = await api.getPage(url, pagenr, options);\n      } else {\n        console.error(`Failed retry on unkown page for ${url}`);\n      }\n    }\n    if (p.ok) {\n      console.log(`Recieved ${url} page: ${pagenr}`);\n      return callback(p);\n    } else {\n      printHeaders(p.headers, console.log);\n      console.error(`Failed to get ${url} page (${p.status}): ${pagenr}`);\n    }\n  }));\n}\n\nasync function getAll42Cursus(api: Fast42) {\n  return getAll42(api, \"/cursus\", {}, async (page) =\u003e {\n    (await page.json() as any).forEach(async (c: any) =\u003e {\n      // Insert `c` into DB\n    })\n  }).then(async () =\u003e {\n    console.log(`Total: ${/* Cursus count from db*/} Cursi`)\n  })\n}\n\n// Using 2 keys here, but with 8 req/s per key it will might be a bit too fast ;)\nasync function main() {\n  const api = await new Fast42([\n    {\n      client_id: process.env['FTAPI_UID'],\n      client_secret: process.env['FTAPI_SECRET'],\n    },\n    {\n      client_id: process.env['FTAPI_UID1'],\n      client_secret: process.env['FTAPI_SECRET1'],\n    }\n  ], 1).init()\n  await getAll42Cursus(api);\n}\n```\n\nUsage with redis:\n```ts\n    const api = await (new Fast42([\n      {\n        client_id: process.env['FTAPI_UID'],\n        client_secret: process.env['FTAPI_SECRET'],\n      },\n    ],\n    0,\n    20000, // setting an expiration on all jobs is important when clustering!\n    {\n        host: \"127.0.0.1\",\n        port: 6379,\n        password: \"somepassword\"\n    }).init());\n    const job = await api.get(\"/projects/1\");    \n    const item = await job.json();\n\n    await api.disconnect();\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodam-coding-college%2Ffast42-ts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcodam-coding-college%2Ffast42-ts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodam-coding-college%2Ffast42-ts/lists"}