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
8 changes: 8 additions & 0 deletions .changeset/docs-use-case-nav.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@dfsync/client': patch
---

Restructure the README around use cases: add a concise "Documentation" section with
guides grouped by use case (reliable requests, validation & data shape, observability &
tracing, extensibility) and a prominent pointer to the full documentation site. Content is
unchanged; only navigation was added.
11 changes: 11 additions & 0 deletions .changeset/error-metadata.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'@dfsync/client': minor
---

Attach request context metadata to thrown errors. Every error that extends `DfsyncError`
(`HttpError`, `NetworkError`, `TimeoutError`, `ValidationError`, `RequestAbortedError`) now
carries optional `requestId`, `attempt`, and `durationMs` fields describing the request
that failed, so callers can correlate failures without lifecycle hooks. Response details
remain available on `HttpError` and `ValidationError` via their existing fields. Backward
compatible — the fields are optional, error constructors are unchanged, and errors created
outside a request lifecycle leave them undefined.
10 changes: 10 additions & 0 deletions .changeset/extension-interfaces.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@dfsync/client': minor
---

Add stable public extension interfaces. Formalize the auth provider contract as
`AuthProvider` (and export `AuthContext`), and add a `TelemetryExporter` interface with a
`createTelemetryHooks(exporter)` helper that maps an exporter onto a standard `HooksConfig`
— no new runtime path in the core. Together with the already-exported `ValidationAdapter`
(validation adapter interface) and `RetryPredicate` (retry policy interface), these form
the minimal, version-stable extension surface. All additive and backward compatible.
9 changes: 9 additions & 0 deletions .changeset/operation-name.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@dfsync/client': minor
---

Add optional `operationName` request option. It is part of the request context and is
exposed in all lifecycle hooks (`beforeRequest`, `afterResponse`, `onRetry`, `onError`),
making it useful for logging, tracing, and telemetry. It is metadata only and does not
affect request behavior. Backward compatible — the field is optional and omitted from
hook contexts when not provided.
16 changes: 16 additions & 0 deletions .changeset/retry-model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
'@dfsync/client': minor
---

Extend the retry model with an overall retry budget, jitter, and custom retry conditions:

- `retry.maxElapsedMs` — caps total time spent retrying (measured from the first attempt);
when the next delay would exceed the budget, the last error is thrown instead of waiting.
- `retry.jitter` — applies full jitter to backoff delays to spread retries and avoid retry
storms. Disabled by default and never applied to server-directed `Retry-After` delays.
- `retry.shouldRetry` — an optional predicate consulted only after the built-in rules
already allow a retry, so it can further restrict retries but never make non-retryable
errors (validation failures, `4xx`) retryable.

Backward compatible — all new options are optional, defaults are unchanged, and existing
`Retry-After` handling and retry semantics are preserved.
17 changes: 17 additions & 0 deletions .changeset/serializer-parser.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'@dfsync/client': minor
---

Add serializer and parser extensibility. Two optional hooks let you override the default
JSON pipeline at the client or request level:

- `serializeBody(body, ctx)` — turns a request body into a `fetch`-compatible body and may
suggest a `contentType` (applied only when the caller has not set one). Called only when
a body is present.
- `parseResponse(response, ctx)` — turns a response into data. It runs for every response
(successful and error) before classification and validation, so `HttpError.data` and
`validateResponse` both operate on the parsed value.

Backward compatible — both options are optional and the default behavior (JSON for object
bodies, content-type-based parsing, `204` → `undefined`) is preserved when they are not
configured. Error handling and validation stages are unchanged.
17 changes: 17 additions & 0 deletions .changeset/validation-adapter-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'@dfsync/client': minor
---

Add a stable validation adapter API via `responseSchema`. It accepts a `safeParse`-style
`ValidationAdapter` returning `{ success, data?, error? }`; when `success` is `false` the
client throws a `ValidationError` and surfaces the adapter's `error` on the new
`ValidationError.issues` field. Validation still runs only after successful responses,
after parsing, and never triggers retries.

Precedence between `responseSchema` and the existing `validateResponse` predicate is
explicit: a request-level option beats a client-level one, and within the same level
`responseSchema` beats `validateResponse`. In this version validation does not replace the
response — the original parsed data is returned.

Backward compatible — `responseSchema` and `ValidationError.issues` are optional and the
existing `validateResponse` behavior is unchanged.
9 changes: 9 additions & 0 deletions .changeset/zod-adapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@dfsync/client': minor
---

Add a zod validation adapter available from the `@dfsync/client/adapters/zod` subpath.
`zodAdapter(schema)` wraps a zod schema into a `responseSchema` `ValidationAdapter`; on
failure the zod error is surfaced on `ValidationError.issues`. `zod` is an optional peer
dependency and the adapter adds no runtime dependency to the core package — it is typed
structurally against `safeParse`, so it works across zod versions.
6 changes: 4 additions & 2 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ Delivered:

Focus: stabilizing core APIs, improving extensibility, and preparing `@dfsync/client` for production-scale usage and future SaaS integration.

Planned features:
Status: completed

Delivered:

- stable validation API (finalized `responseSchema` contract)
- validation must run after response parsing
Expand All @@ -91,7 +93,7 @@ Planned features:
- `HttpError`
- `NetworkError`
- `TimeoutError`
- `AbortError`
- `RequestAbortedError`
- `ValidationError`
- must preserve backward compatibility
- must not change existing error inheritance unexpectedly
Expand Down
1 change: 1 addition & 0 deletions examples/node-basic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ pnpm example:bearer-auth
pnpm example:hooks
pnpm example:custom-auth
pnpm example:retry
pnpm example:serializer
```
3 changes: 2 additions & 1 deletion examples/node-basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"example:bearer-auth": "tsx bearer-auth.ts",
"example:hooks": "tsx hooks.ts",
"example:custom-auth": "tsx custom-auth.ts",
"example:retry": "tsx retry.ts"
"example:retry": "tsx retry.ts",
"example:serializer": "tsx serializer.ts"
},
"dependencies": {
"@dfsync/client": "workspace:*"
Expand Down
4 changes: 4 additions & 0 deletions examples/node-basic/retry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ const client = createClient({
attempts: 2,
backoff: 'exponential',
baseDelayMs: 300,
// Spread retries with full jitter to avoid retry storms.
jitter: true,
// Cap the total time spent retrying, measured from the first attempt.
maxElapsedMs: 5_000,
},
});

Expand Down
34 changes: 34 additions & 0 deletions examples/node-basic/serializer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { createClient } from '@dfsync/client';

// A client that sends form-encoded bodies and parses form-encoded responses,
// instead of the default JSON behavior.
const client = createClient({
baseUrl: 'https://httpbin.org',
serializeBody(body) {
return {
body: new URLSearchParams(body as Record<string, string>).toString(),
contentType: 'application/x-www-form-urlencoded',
};
},
async parseResponse(response) {
const text = await response.text();

try {
return JSON.parse(text);
} catch {
return text;
}
},
});

async function main() {
try {
const result = await client.post('/post', { name: 'Roman', role: 'backend' });

console.log('Response:', result);
} catch (error) {
console.error('Request failed:', error);
}
}

main();
8 changes: 7 additions & 1 deletion packages/client/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ Do NOT:

## Current focus

Release: 0.9.x — Platform readiness & API stabilization
Release: 1.0.x — Stable core & production readiness

0.9.x (Platform readiness & API stabilization) is complete: `operationName`, extended error
metadata, improved retry model (`maxElapsedMs`, jitter, custom `shouldRetry`), serializer /
parser extensibility, the `responseSchema` validation adapter API with a zod adapter, and
the stable public extension interfaces (auth provider, validation adapter, retry policy,
telemetry exporter).

Always check the root `ROADMAP.md` before making release-related changes.
Loading
Loading