npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ibertran/fortytwo-intra-client

v3.2.0

Published

A TypeScript library for interacting with the 42API with built-in rate limiting, automatic token management, and retry logic.

Readme

FortytwoIntraClient

A TypeScript library for interacting with the 42API with built-in rate limiting, automatic token management, and retry logic.

Installation

npm install @ibertran/fortytwo-intra-client

Quick Start

import { FortytwoIntraClient } from '@ibertran/fortytwo-intra-client';

const client = new FortytwoIntraClient('your_client_id', 'your_client_secret');


// Get a specific user by login
const user = await client.get('users/ibertran');
console.log(user);

Configuration

The FortytwoIntraClient class accepts three parameters:

  1. client_id (required): Your 42 API client ID
  2. client_secret (required): Your 42 API client secret
  3. config (optional): Configuration object

Configuration Options

interface FortytwoIntraClientConf {
  redirect_uri: string | null;           // OAuth redirect URI (default: null)
  base_url: string;                      // API base URL (default: "https://api.intra.42.fr/v2/")
  token_url: string;                     // Token endpoint (default: "https://api.intra.42.fr/oauth/token")
  oauth_url: string;                     // OAuth endpoint (default: "https://api.intra.42.fr/oauth/authorize")
  token_info_url: string;                // Token info endpoint (default: "https://api.intra.42.fr/oauth/token/info")
  scopes: string[];                      // OAuth scopes (default: ["public"])
  rateLimitMaxRequests: number;          // Max requests per time window (default: 2)
  rateLimitPerMilliseconds: number;      // Time window in milliseconds (default: 1200)
  maxRetry: number;                      // Max retry attempts (default: 5)
  logLine: boolean;                      // Enable request logging (default: true)
  errLogBody: boolean;                   // Log error response bodies (default: true)
}

Example with Custom Configuration

const client = new FortytwoIntraClient('your_client_id', 'your_client_secret', {
  rateLimitMaxRequests: 1,              // 1 request per 1200ms
  rateLimitPerMilliseconds: 1200,       // Time window
  maxRetry: 3,                          // Retry up to 3 times
  logLine: false,                       // Disable logging
  errLogBody: false,                    // Disable error body logging
  scopes: ['public', 'projects']        // Extended scopes
});

API Methods

GET Requests

// Get all campuses
const campuses = await client.get('campus');
console.log(`Found ${campuses.length} campuses`);

// Get a specific campus
const lyonCampus = await client.get('campus/9');
console.log(`${lyonCampus.name}: ${lyonCampus.users_count} users`);

POST Requests

// Create a team for a project
const team = await client.post('teams', {
  body: {
    name: 'awesome-team',
    project_id: 42
  }
});

PATCH Requests

// Update a team name
const updatedTeam = await client.patch('teams/123', {
  body: {
		team: {
			name: "updated-team-name"
		}
  }
});

DELETE Requests

// Delete a team
await client.delete('teams/123');

Get All Pages (Pagination Helper)

The getAll method automatically handles pagination and returns all results:

// Get all users from 42Lyon (handles pagination automatically)
const lyonUsers = await client.getAll('campus/9/users');
console.log(`42Lyon campus has ${lyonUsers.length} users`);

// Get all projects with custom page size
const allProjects = await client.getAll('projects', {
  perPage: 50  // 50 items per page (default: 100)
});

OAuth Authentication

Authorization Flow

// 1. Get OAuth authorization URL
const authUrl = client.getOAuthUrl('http://localhost:3000/callback');
// Redirect user to authUrl

// 2. Exchange authorization code for tokens
const tokens = await client.exchangeOAuthCode(code, 'http://localhost:3000/callback');
// tokens contains: access_token, refresh_token, expires_in, etc.

// 3. Use tokens for authenticated requests (USER-SPECIFIC DATA)
const currentUser = await client.get('users/me', {
  token: tokens
});
console.log(`Welcome ${currentUser.displayname}!`);

Using Custom Redirect URI

// Set redirect URI in constructor
const client = new IntraApiProxy('client_id', 'client_secret', {
  redirect_uri: 'http://localhost:3000/callback'
});

// Or pass it to getOAuthUrl
const authUrl = client.getOAuthUrl('http://localhost:3000/callback');

Utility Methods

URL Builder

// Create a URL object for the API
const userUrl = client.URL('users/jdoe');
console.log(userUrl.toString()); // "https://api.intra.42.fr/v2/users/jdoe"

// Build URLs for specific endpoints
const campusUrl = client.URL('campus/1/users');
const projectUrl = client.URL('projects/libft');
const coalitionUrl = client.URL('coalitions/1/users');

Error Handling

The library includes automatic retry logic for rate limiting (429) and authentication (401) errors:

try {
  const user = await client.get('users/jdoe');
  console.log(`Found user: ${user.displayname}`);
} catch (error) {
  if (error.status === 404) {
    console.error('User not found');
  } else if (error.status === 403) {
    console.error('Access forbidden - check your token permissions');
  } else {
    console.error('Request failed after retries:', error.message);
  }
}

Rate Limiting

Requests are automatically throttled based on the configured rate limit. The default is 2 requests per second to comply with 42's API limits.

Logging

By default, the library logs all requests with colored status codes and formatted parameters:

200 GET    /v2/users/jdoe
200 GET    /v2/campus { filter: { city: 'lyon' } }
429 GET    /v2/projects
200 GET    /v2/projects retry 1/5

Disable logging by setting logLine: false in the configuration. Control error body logging with errLogBody: false.

TypeScript Support

This library is written in TypeScript and includes full type definitions:

import { FortytwoIntraClient } from '@ibertran/fortytwo-intra-client';

// Types are automatically inferred
const client = new FortytwoIntraClient('client_id', 'client_secret');

OAuth Flow Example

import express from 'express';
import { FortytwoIntraClient } from '@ibertran/fortytwo-intra-client';

const app = express();
const client = new FortytwoIntraClient(
  process.env.INTRA_CLIENT_ID!,
  process.env.INTRA_CLIENT_SECRET!,
  { 
    redirect_uri: 'http://localhost:3000/callback',
    oauth_scope: ['public']
  }
);

// Redirect to 42 OAuth
app.get('/login', (req, res) => {
  const authUrl = client.getOAuthUrl();
  res.redirect(authUrl);
});

// Handle OAuth callback
app.get('/callback', async (req, res) => {
  try {
    const { code } = req.query;
    const token = await client.exchangeOAuthCode(code as string);
    
    // Use tokens to make authenticated requests (accessing personal data)
    const userData = await client.get('users/me', { token: token });
        
    res.json({ 
      user: {
        login: userData.login,
        displayname: userData.displayname,
        email: userData.email,
        level: userData.cursus_users[0]?.level || 0,
        wallet: userData.wallet,
        campus: userData.campus[0]?.name
      },
    });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.listen(3000, () => {
  console.log('Server running on http://localhost:3000');
  console.log('Visit http://localhost:3000/login to start OAuth flow');
});