Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions clients/SPECS.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
- Token-based bearer authentication with an extensibility seam for future auth
strategies (OAuth2, mTLS, rotating providers).
- Public (unauthenticated) monitoring endpoints: `ping`, `pings`,
`ping_provider` (see §9.5).
`ping_provider` (see §9.6).

**Out of scope**

Expand Down Expand Up @@ -177,6 +177,14 @@ The client's `Response` object MUST expose, at minimum:

`Response` is a value object: no side effects, stable field order.

### Binary responses

Some endpoints return a binary document instead of the JSON envelope (e.g.
`application/pdf` attestations). Clients MUST parse the body as JSON only when
the response `Content-Type` is a JSON media type **or absent**; otherwise `raw`
exposes the bytes verbatim, `data` is null/undefined and `links`/`meta` are
empty.

---

## 6. Error handling — JSON:API
Expand Down Expand Up @@ -445,7 +453,16 @@ brackets:
client.dss.allocation_adulte_handicape_identite(prenoms: ['Jean', 'Paul'], …)
```

### 9.5 Public (unauthenticated) endpoints — Ping
### 9.5 Request-header parameters

Operations may declare `in: header` parameters (e.g. `X-Generate-Proof` on the
EAJE identity endpoint). Generated methods MUST expose each one as an optional
kwarg named after the header — lowercased, dashes to underscores, leading `x_`
stripped (`X-Generate-Proof` → `generate_proof`) — and send the value verbatim
as a request header when provided. `Cache-Control` is transport-level and MUST
NOT be scaffolded.

### 9.6 Public (unauthenticated) endpoints — Ping

Both APIs expose monitoring endpoints marked `security: []` in the OpenAPI
spec. These endpoints require **no token**, **no audit parameters**
Expand Down Expand Up @@ -748,7 +765,7 @@ A reviewer certifying a new client ticks each item.
`User-Agent` set.
- [ ] Immutable `Configuration` with `with()` / `copy()`; ENV vars honoured.
- [ ] Public ping endpoints (`ping`, `pings`, `ping_provider`) exposed on
the client; no auth header or audit params sent (§9.5).
the client; no auth header or audit params sent (§9.6).
- [ ] Unit tests cover every surface listed in §12.1; integration tests
cover 200 / 422 / 429 / 502 on both APIs; staging conformance run
from TESTING.md passes; README has a stub example.
Expand Down
4 changes: 2 additions & 2 deletions clients/node/api-entreprise/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c39093e4bc410efcbe528a7b462142c8c4d7f0a6).
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c5278ec9bf7b37c6ac9b435ebbcf314ea9f2882c).
// Regenerate via clients/node/bin/sync-commons.ts

import type { AuthStrategy } from './strategy.js';
Expand Down
2 changes: 1 addition & 1 deletion clients/node/api-entreprise/src/commons/auth/strategy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c39093e4bc410efcbe528a7b462142c8c4d7f0a6).
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c5278ec9bf7b37c6ac9b435ebbcf314ea9f2882c).
// Regenerate via clients/node/bin/sync-commons.ts

export interface AuthStrategy {
Expand Down
63 changes: 28 additions & 35 deletions clients/node/api-entreprise/src/commons/client-base.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c39093e4bc410efcbe528a7b462142c8c4d7f0a6).
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c5278ec9bf7b37c6ac9b435ebbcf314ea9f2882c).
// Regenerate via clients/node/bin/sync-commons.ts

import { Configuration, type Logger } from './configuration.js';
Expand Down Expand Up @@ -175,23 +175,7 @@ export abstract class ClientBase {
const responseHeaders = headersToRecord(fetchResponse.headers);
const rateLimit = RateLimit.fromHeaders(fetchResponse.headers);

let body: unknown;
const text = await fetchResponse.text();
if (text) {
try {
body = JSON.parse(text);
} catch {
if (fetchResponse.ok) {
throw new TransportError(
`invalid JSON body: ${text.slice(0, 200)}`,
{ method, url },
);
}
body = {};
}
} else {
body = {};
}
const body: unknown = await this.parseBody(fetchResponse, method, url);

this.logRequest(method, url, fetchResponse.status, durationMs, rateLimit);

Expand Down Expand Up @@ -256,23 +240,7 @@ export abstract class ClientBase {
const durationMs = Date.now() - started;
const responseHeaders = headersToRecord(fetchResponse.headers);

let body: unknown;
const text = await fetchResponse.text();
if (text) {
try {
body = JSON.parse(text);
} catch {
if (fetchResponse.ok) {
throw new TransportError(
`invalid JSON body: ${text.slice(0, 200)}`,
{ method, url },
);
}
body = {};
}
} else {
body = {};
}
const body: unknown = await this.parseBody(fetchResponse, method, url);

this.logRequest(method, url, fetchResponse.status, durationMs, null);

Expand Down Expand Up @@ -351,6 +319,31 @@ export abstract class ClientBase {
return result;
}

private async parseBody(
fetchResponse: globalThis.Response,
method: string,
url: string,
): Promise<unknown> {
const contentType = fetchResponse.headers.get('content-type') ?? '';
if (contentType && !contentType.includes('json')) {
return new Uint8Array(await fetchResponse.arrayBuffer());
}

const text = await fetchResponse.text();
if (!text) return {};
try {
return JSON.parse(text);
} catch {
if (fetchResponse.ok) {
throw new TransportError(
`invalid JSON body: ${text.slice(0, 200)}`,
{ method, url },
);
}
return {};
}
}

private throwMappedError(
status: number,
body: unknown,
Expand Down
2 changes: 1 addition & 1 deletion clients/node/api-entreprise/src/commons/configuration.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c39093e4bc410efcbe528a7b462142c8c4d7f0a6).
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c5278ec9bf7b37c6ac9b435ebbcf314ea9f2882c).
// Regenerate via clients/node/bin/sync-commons.ts

import type { AuthStrategy } from './auth/strategy.js';
Expand Down
2 changes: 1 addition & 1 deletion clients/node/api-entreprise/src/commons/errors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c39093e4bc410efcbe528a7b462142c8c4d7f0a6).
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c5278ec9bf7b37c6ac9b435ebbcf314ea9f2882c).
// Regenerate via clients/node/bin/sync-commons.ts

export interface JsonApiError {
Expand Down
2 changes: 1 addition & 1 deletion clients/node/api-entreprise/src/commons/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c39093e4bc410efcbe528a7b462142c8c4d7f0a6).
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c5278ec9bf7b37c6ac9b435ebbcf314ea9f2882c).
// Regenerate via clients/node/bin/sync-commons.ts

export { type AuthStrategy } from './auth/strategy.js';
Expand Down
2 changes: 1 addition & 1 deletion clients/node/api-entreprise/src/commons/rate-limit.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c39093e4bc410efcbe528a7b462142c8c4d7f0a6).
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c5278ec9bf7b37c6ac9b435ebbcf314ea9f2882c).
// Regenerate via clients/node/bin/sync-commons.ts

/** Parsed RateLimit-* response headers. */
Expand Down
16 changes: 10 additions & 6 deletions clients/node/api-entreprise/src/commons/response.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c39093e4bc410efcbe528a7b462142c8c4d7f0a6).
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c5278ec9bf7b37c6ac9b435ebbcf314ea9f2882c).
// Regenerate via clients/node/bin/sync-commons.ts

import { RateLimit } from './rate-limit.js';

/** Parsed API response with envelope fields (data, links, meta) and rate limit info. */
export class Response {
readonly raw: Record<string, unknown>;
readonly raw: Record<string, unknown> | Uint8Array;
readonly httpStatus: number;
readonly headers: Record<string, string>;
readonly rateLimit: RateLimit | null;
Expand All @@ -16,22 +16,26 @@ export class Response {
headers: Record<string, string>;
rateLimit?: RateLimit | null;
}) {
this.raw = isRecord(options.raw) ? options.raw : {};
this.raw = options.raw instanceof Uint8Array || isRecord(options.raw) ? options.raw : {};
this.httpStatus = options.httpStatus;
this.headers = options.headers;
this.rateLimit = options.rateLimit ?? null;
}

get data(): unknown {
return this.raw['data'];
return this.envelope['data'];
}

get links(): Record<string, unknown> {
return (this.raw['links'] as Record<string, unknown>) ?? {};
return (this.envelope['links'] as Record<string, unknown>) ?? {};
}

get meta(): Record<string, unknown> {
return (this.raw['meta'] as Record<string, unknown>) ?? {};
return (this.envelope['meta'] as Record<string, unknown>) ?? {};
}

private get envelope(): Record<string, unknown> {
return this.raw instanceof Uint8Array ? {} : this.raw;
}

get success(): boolean {
Expand Down
2 changes: 1 addition & 1 deletion clients/node/api-entreprise/src/commons/siren.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c39093e4bc410efcbe528a7b462142c8c4d7f0a6).
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c5278ec9bf7b37c6ac9b435ebbcf314ea9f2882c).
// Regenerate via clients/node/bin/sync-commons.ts

import { InvalidSirenError } from './errors.js';
Expand Down
2 changes: 1 addition & 1 deletion clients/node/api-entreprise/src/commons/siret.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c39093e4bc410efcbe528a7b462142c8c4d7f0a6).
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c5278ec9bf7b37c6ac9b435ebbcf314ea9f2882c).
// Regenerate via clients/node/bin/sync-commons.ts

import { InvalidSiretError } from './errors.js';
Expand Down
2 changes: 1 addition & 1 deletion clients/node/api-entreprise/src/commons/user-agent.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c39093e4bc410efcbe528a7b462142c8c4d7f0a6).
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c5278ec9bf7b37c6ac9b435ebbcf314ea9f2882c).
// Regenerate via clients/node/bin/sync-commons.ts

const URL = 'https://github.com/datagouv/apistration';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c39093e4bc410efcbe528a7b462142c8c4d7f0a6).
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c5278ec9bf7b37c6ac9b435ebbcf314ea9f2882c).
// Regenerate via clients/node/bin/sync-commons.ts

import type { AuthStrategy } from './strategy.js';
Expand Down
2 changes: 1 addition & 1 deletion clients/node/api-particulier/src/commons/auth/strategy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c39093e4bc410efcbe528a7b462142c8c4d7f0a6).
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c5278ec9bf7b37c6ac9b435ebbcf314ea9f2882c).
// Regenerate via clients/node/bin/sync-commons.ts

export interface AuthStrategy {
Expand Down
63 changes: 28 additions & 35 deletions clients/node/api-particulier/src/commons/client-base.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c39093e4bc410efcbe528a7b462142c8c4d7f0a6).
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c5278ec9bf7b37c6ac9b435ebbcf314ea9f2882c).
// Regenerate via clients/node/bin/sync-commons.ts

import { Configuration, type Logger } from './configuration.js';
Expand Down Expand Up @@ -175,23 +175,7 @@ export abstract class ClientBase {
const responseHeaders = headersToRecord(fetchResponse.headers);
const rateLimit = RateLimit.fromHeaders(fetchResponse.headers);

let body: unknown;
const text = await fetchResponse.text();
if (text) {
try {
body = JSON.parse(text);
} catch {
if (fetchResponse.ok) {
throw new TransportError(
`invalid JSON body: ${text.slice(0, 200)}`,
{ method, url },
);
}
body = {};
}
} else {
body = {};
}
const body: unknown = await this.parseBody(fetchResponse, method, url);

this.logRequest(method, url, fetchResponse.status, durationMs, rateLimit);

Expand Down Expand Up @@ -256,23 +240,7 @@ export abstract class ClientBase {
const durationMs = Date.now() - started;
const responseHeaders = headersToRecord(fetchResponse.headers);

let body: unknown;
const text = await fetchResponse.text();
if (text) {
try {
body = JSON.parse(text);
} catch {
if (fetchResponse.ok) {
throw new TransportError(
`invalid JSON body: ${text.slice(0, 200)}`,
{ method, url },
);
}
body = {};
}
} else {
body = {};
}
const body: unknown = await this.parseBody(fetchResponse, method, url);

this.logRequest(method, url, fetchResponse.status, durationMs, null);

Expand Down Expand Up @@ -351,6 +319,31 @@ export abstract class ClientBase {
return result;
}

private async parseBody(
fetchResponse: globalThis.Response,
method: string,
url: string,
): Promise<unknown> {
const contentType = fetchResponse.headers.get('content-type') ?? '';
if (contentType && !contentType.includes('json')) {
return new Uint8Array(await fetchResponse.arrayBuffer());
}

const text = await fetchResponse.text();
if (!text) return {};
try {
return JSON.parse(text);
} catch {
if (fetchResponse.ok) {
throw new TransportError(
`invalid JSON body: ${text.slice(0, 200)}`,
{ method, url },
);
}
return {};
}
}

private throwMappedError(
status: number,
body: unknown,
Expand Down
2 changes: 1 addition & 1 deletion clients/node/api-particulier/src/commons/configuration.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c39093e4bc410efcbe528a7b462142c8c4d7f0a6).
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c5278ec9bf7b37c6ac9b435ebbcf314ea9f2882c).
// Regenerate via clients/node/bin/sync-commons.ts

import type { AuthStrategy } from './auth/strategy.js';
Expand Down
2 changes: 1 addition & 1 deletion clients/node/api-particulier/src/commons/errors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c39093e4bc410efcbe528a7b462142c8c4d7f0a6).
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c5278ec9bf7b37c6ac9b435ebbcf314ea9f2882c).
// Regenerate via clients/node/bin/sync-commons.ts

export interface JsonApiError {
Expand Down
2 changes: 1 addition & 1 deletion clients/node/api-particulier/src/commons/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c39093e4bc410efcbe528a7b462142c8c4d7f0a6).
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c5278ec9bf7b37c6ac9b435ebbcf314ea9f2882c).
// Regenerate via clients/node/bin/sync-commons.ts

export { type AuthStrategy } from './auth/strategy.js';
Expand Down
2 changes: 1 addition & 1 deletion clients/node/api-particulier/src/commons/rate-limit.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c39093e4bc410efcbe528a7b462142c8c4d7f0a6).
// DO NOT EDIT — generated from clients/node/commons/src/ (source digest: c5278ec9bf7b37c6ac9b435ebbcf314ea9f2882c).
// Regenerate via clients/node/bin/sync-commons.ts

/** Parsed RateLimit-* response headers. */
Expand Down
Loading
Loading