{"_id":"@42paris/intraoapi42","_rev":"3-b14a02afe083f47e7789405714bd427a","name":"@42paris/intraoapi42","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@42paris/intraoapi42","version":"1.0.0","author":{"name":"42paris"},"license":"MIT","_id":"@42paris/intraoapi42@1.0.0","maintainers":[{"name":"froz42","email":"froz@42.fr"},{"name":"blast42","email":"blast@42paris.fr"}],"homepage":"https://github.com/blast42/intraoapi42#readme","bugs":{"url":"https://github.com/blast42/intraoapi42/issues"},"dist":{"shasum":"b3d4848422f5751b1a687dc97c0c7d965ea4b34f","tarball":"https://registry.npmjs.org/@42paris/intraoapi42/-/intraoapi42-1.0.0.tgz","fileCount":18,"integrity":"sha512-Gz1SKO1S0z9TKKxJav6hbZ/RqLBMW/uEjEgKNyboSHf8Qb+YZWR62I9Bpv2mNdA+DAx9yUKdqpJAG8JVJ1uv1w==","signatures":[{"sig":"MEUCIACAvLuFdrB31DBbS5UpkuRlLRfkzTO+3YoDdkhkYo2mAiEA3TyXSRLh4m4Mj/aQi4BwEQJHkrfBD0LICt1Jqjt6ZAU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":214125},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"f4a66b11b6213e80f96ffdfb524a882dbdee93e6","scripts":{"build":"tsc","release":"semantic-release","typecheck":"tsc --noEmit","generate:api":"openapi-typescript openapi.yaml --output ./src/types.ts","prepublishOnly":"npm run build"},"_npmUser":{"name":"blast42","email":"blast@42paris.fr"},"repository":{"url":"git+https://github.com/blast42/intraoapi42.git","type":"git"},"_npmVersion":"10.9.7","description":"Typed API client for the 42 Intra API","directories":{},"_nodeVersion":"22.22.2","dependencies":{"openapi-fetch":"^0.17.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.23.12","typescript":"^5.9.2","semantic-release":"^25.0.9","openapi-typescript":"^7.13.0","@semantic-release/npm":"^13.1.5","@semantic-release/github":"^12.0.9","@semantic-release/commit-analyzer":"^13.0.1","@semantic-release/release-notes-generator":"^14.1.1"},"_npmOperationalInternal":{"tmp":"tmp/intraoapi42_1.0.0_1788171384487_0.6371892683294638","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2026-08-31T10:16:24.231Z","modified":"2026-09-08T14:17:22.109Z","1.0.0":"2026-08-31T10:16:24.624Z"},"bugs":{"url":"https://github.com/blast42/intraoapi42/issues"},"author":{"name":"42paris"},"license":"MIT","homepage":"https://github.com/blast42/intraoapi42#readme","repository":{"url":"git+https://github.com/blast42/intraoapi42.git","type":"git"},"description":"Typed API client for the 42 Intra API","maintainers":[{"email":"froz@42.fr","name":"froz42"},{"email":"blast@42paris.fr","name":"blast42"},{"email":"reach@42paris.fr","name":"reach42"},{"email":"eva@42paris.fr","name":"zouz"}],"readme":"# intraoapi42\n\nTyped TypeScript client for the [42 Intra API](https://api.intra.42.fr/), built on [`openapi-fetch`](https://openapi-ts.dev/packages/openapi-fetch/).\n\nFeatures:\n\n- Fully typed requests and responses generated from the OpenAPI spec.\n- Automatic OAuth2 client credentials flow with token refresh.\n- Built‑in retry logic for transient failures.\n- Ready‑made configs for production and staging environments.\n\n---\n\n## Installation\n\n```bash\nnpm install intraoapi42\n```\n\nor with a scoped name if you publish as such:\n\n```bash\nnpm install @your-username/intraoapi42\n```\n\nRequires Node.js with ESM support (your `package.json` should have `\"type\": \"module\"` or use `.mjs` extensions).\n\n---\n\n## Quick start\n\n```ts\nimport {\n  createApiClient,\n  ProductionConfig,\n  withClientCredentials,\n  withScopes,\n} from \"intraoapi42\";\n\n// Configure OAuth2 client credentials\nconst config = withClientCredentials(\n  ProductionConfig,\n  \"YOUR_CLIENT_ID\",\n  \"YOUR_CLIENT_SECRET\",\n);\n\n// Optionally restrict scopes\nconst scopedConfig = withScopes(\n  config,\n  \"public\",\n  \"projects\",\n);\n\n// Create the API client\nconst api = createApiClient(scopedConfig);\n\n// Example: GET /v2/users/:id\nconst { data, error } = await api.GET(\"/users/{id}\", {\n  params: {\n    path: { id: 12345 },\n  },\n});\n\nif (error) {\n  throw new Error(`API error: ${error.message}`);\n}\n\nconsole.log(data);\n```\n\nTypes for paths, parameters, and responses are inferred from the OpenAPI spec, so you get full TypeScript autocomplete and type checking.\n\n---\n\n## Configuration\n\n### Environments\n\nTwo built‑in configs are provided:\n\n```ts\nimport { ProductionConfig, StagingConfig } from \"intraoapi42\";\n\nProductionConfig;\n// {\n//   tokenUrl: \"https://api.intra.42.fr/oauth/token\",\n//   serverUrl: \"https://api.intra.42.fr/v2\",\n// }\n\nStagingConfig;\n// {\n//   tokenUrl: \"https://api.intra-staging.42.fr/oauth/token\",\n//   serverUrl: \"https://api.intra-staging.42.fr/v2\",\n// }\n```\n\n### Adding credentials\n\nUse `withClientCredentials` to attach your OAuth2 client ID and secret:\n\n```ts\nimport {\n  ProductionConfig,\n  withClientCredentials,\n  createApiClient,\n} from \"intraoapi42\";\n\nconst config = withClientCredentials(\n  ProductionConfig,\n  process.env.INTRA_CLIENT_ID!,\n  process.env.INTRA_CLIENT_SECRET!,\n);\n\nconst api = createApiClient(config);\n```\n\n### Adding scopes\n\nOptionally restrict the token’s scopes:\n\n```ts\nimport { withScopes } from \"intraoapi42\";\n\nconst config = withScopes(\n  ProductionConfig,\n  \"public\",\n  \"projects\",\n  \"activities\",\n);\n```\n\nScopes are passed to the token endpoint as a space‑separated string.\n\n---\n\n## How authentication works\n\n`createApiClient` sets up:\n\n- A **refreshable token source** that:\n  - Requests a new access token using client credentials when needed.\n  - Caches the token until close to expiry (with a 60s safety margin).\n  - Deduplicates concurrent token requests.\n- An **auth middleware** that:\n  - Adds `Authorization: Bearer <token>` to every request.\n  - On `401 Unauthorized`, invalidates the cached token, fetches a fresh one, and retries the request once.\n\nYou don’t need to manage tokens manually; just use the client.\n\n---\n\n## Usage patterns\n\n### List users with pagination\n\n```ts\nconst { data, error } = await api.GET(\"/users\", {\n  params: {\n    query: {\n      page_size: 50,\n      page: 1,\n    },\n  },\n});\n\nif (error) {\n  throw new Error(error.message);\n}\n\n// data is typed according to the OpenAPI spec\nconsole.log(data);\n```\n\n### POST / PATCH / DELETE\n\n```ts\n// Example: update a user\nconst { data, error } = await api.PATCH(\"/users/{id}\", {\n  params: {\n    path: { id: 12345 },\n  },\n  body: {\n    // typed fields here\n    displayname: \"New Name\",\n  },\n});\n```\n\nAll HTTP methods (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`, etc.) are available with full typing.\n\n---\n\n## Error handling\n\nEach call returns `{ data, error }`:\n\n- `data` is defined when the request succeeds.\n- `error` is defined when the request fails (network error, non‑2xx response, etc.).\n\n```ts\nconst { data, error } = await api.GET(\"/users/{id}\", {\n  params: { path: { id: 12345 } },\n});\n\nif (error) {\n  // error has shape: { message, body?, response, ... }\n  console.error(\"Status:\", error.response.status);\n  console.error(\"Body:\", await error.response.clone().text());\n  throw new Error(\"Failed to fetch user\");\n}\n\n// Use data safely\nconsole.log(data.id, data.login);\n```\n\nRefer to `openapi-fetch` docs for the exact error shape and advanced patterns.\n\n---\n\n## TypeScript usage\n\nThe package exports types generated from the OpenAPI spec:\n\n```ts\nimport type { paths } from \"intraoapi42\";\n\n// paths describes all available endpoints and their shapes\ntype UsersEndpoint = paths[\"/users\"];\n```\n\nYour IDE will infer types automatically from `api.GET`, `api.POST`, etc., so you usually don’t need to import these manually.\n\n---\n\n## Development / Contributing\n\nIf you’re working on the client itself:\n\n```bash\ncd clients/typescript\n\n# Install dependencies\nnpm install\n\n# Generate types from OpenAPI spec\nnpm run generate:api\n\n# Typecheck\nnpm run typecheck\n\n# Build\nnpm run build\n\n# Run tests\nnpm test\n```\n\n---\n\n## License\n\nMIT","readmeFilename":"README.md"}