@defjs/core 0.4.0-beta.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. package/README.md +44 -61
  2. package/index.d.ts +1923 -579
  3. package/index.js +1927 -1419
  4. package/index.min.js +21 -27
  5. package/package.json +2 -1
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # @defjs/core
2
2
 
3
- Type-safe HTTP, SSE, and WebSocket commands for TypeScript.
3
+ Design reusable HTTP, SSE, and WebSocket APIs as data, then execute them with an application-owned client.
4
4
 
5
- This README describes the package version that contains it. Defjs is still pre-1.0, so use the documentation and release notes published for the exact version installed in your application.
5
+ `def` means `define`. An SDK author exports operation definitions and data contracts. The consuming application supplies the endpoint, credentials, interceptors, and transport. Importing a definition starts no request and binds no client.
6
6
 
7
7
  ## Install
8
8
 
@@ -10,79 +10,62 @@ This README describes the package version that contains it. Defjs is still pre-1
10
10
  bun add @defjs/core
11
11
  ```
12
12
 
13
- The package is ESM and declares no runtime dependencies. Its tarball retains this `README.md` and the repository `LICENSE`; repository-wide guides and examples remain outside the package.
13
+ The package is ESM and declares no runtime dependencies. Declarations target `ES2022` with `ESNext.Disposable`, `DOM`, and `DOM.Iterable`; those entries supply types only, not polyfills. Defjs is pre-1.0, so use the documentation for the exact version you installed.
14
14
 
15
- ## Quick Start
15
+ ## Quick start
16
16
 
17
- ```typescript
18
- import { createClient, defineRequest, struct, withEndpoint } from '@defjs/core'
17
+ ```ts
18
+ // users-sdk.ts — SDK definition
19
+ import { defineRequest, struct } from "@defjs/core";
19
20
 
20
- const client = createClient(withEndpoint('https://api.example.com'))
21
-
22
- const getUser = defineRequest({
23
- method: 'GET',
24
- path: '/users/:id',
25
- input: struct.object({
26
- path: struct.object({ id: struct.number() }),
27
- }),
21
+ export const getUser = defineRequest({
22
+ method: "GET",
23
+ path: "/users/:id",
24
+ input: struct.object({ id: struct.number() }),
25
+ builder: (input) => ({ path: input }),
28
26
  output: struct.object({ id: struct.number(), name: struct.string() }),
29
27
  error: struct.object({ message: struct.string() }),
30
- })
31
-
32
- const [error, user] = await client.execute(getUser({ path: { id: 1 } }))
33
-
34
- if (error) {
35
- console.error(String(error), error.code)
36
- } else {
37
- console.log(user.id, user.name)
38
- }
28
+ });
39
29
  ```
40
30
 
41
- `output` is one Struct for the 2xx body; `error` is one Struct for everything else. `ok` is the only fork, and only one side ever decodes. Omit a side and that body is never read.
42
-
43
- ## Core Boundaries
44
-
45
- - Commands are typed values created by `defineRequest`, `defineEventStream`, and `defineWebSocket`.
46
- - Structs validate request input and response data at runtime. A `builder` places parsed input onto `path`, `query`, `headers`, and `body`. Omit it when the input struct already has that shape. `.alias(name)` is the wire name for a typed value.
47
- - Expected failures are returned as native `Fault` instances in an error-first tuple; custom interceptors and application callbacks can still throw. A `Fault` is discriminated by one closed set of `code` values whose prefix is the class — `HTTP_STATUS`, `REQ_*`, `NET_*`, `RES_*`, `EXT_*`, `CAP_*`, `ENV_UNSUPPORTED`. `String(error)` is directly loggable, while `code` and the variant metadata remain enumerable for structured logs.
48
- - Faults carry their underlying value on the native `Error` cause chain. Narrow `error.cause instanceof StructError` before calling Struct-only helpers such as `format()`, `flatten()`, or `prettify()`.
49
- - Server clients that capture cookies, authorization, tenant data, or user data must be created inside the owning request scope.
50
- - Ordinary HTTP work is request-scoped and is bounded with its execute-time timeout or `AbortSignal`; `Client` is not `AsyncDisposable` and has no global `dispose()` lifecycle.
51
- - Returned SSE and WebSocket handles are `AsyncDisposable`, so `await using` waits for Defjs-owned teardown. SSE disposal stops Defjs reading/reconnect work and releases its reader lock, but does not wait forever for a provider-controlled `cancel()` promise.
52
- - WebSocket `closed` is the logical terminal result. Its disposer uses a one-second bounded teardown and may reject with `TimeoutError`; it cannot prove physical TCP closure. Existing `close()` and `closed` APIs remain available for manual lifecycle control.
53
- - A timeout or cancellation does not prove that a server did not receive a write. Preserve operation identity and use an application/server idempotency contract before replaying writes.
54
- - OpenAPI generation, full SDK generation, query caching, and GraphQL protocol handling are not included in this release. Define contracts by hand or compose purpose-built tools at the application boundary.
55
-
56
- For client-local tests, inject a Fetch-compatible function with `withHTTPHandle(...)`. This keeps request interception scoped to one client and still exercises command building, interceptors, status dispatch, and response validation.
57
-
58
- ### WebSocket messages
31
+ ```ts
32
+ // app.ts — application-owned client
33
+ import { createClient, withEndpoint } from "@defjs/core";
34
+ import { getUser } from "./users-sdk.ts";
59
35
 
60
- `incoming` and `outgoing` are each one struct. `session.send` encodes that struct (aliases included) and sends JSON. A frame that is not valid JSON, or does not match `incoming`, is reported to `session.onRuntimeError` and is not delivered. Use `struct.discriminatedUnion` when one socket carries several message kinds. Static subprotocols belong on `protocols`.
36
+ const client = createClient(withEndpoint("https://api.example.com"));
61
37
 
62
- ## Runtime Notes
63
-
64
- Repository development, testing, building, packaging, and publishing use Bun `1.4.0`. The package uses standard Web APIs such as `fetch`, `Request`, `Response`, `Headers`, streams, and `WebSocket` according to the transports enabled by the application. The packed-consumer gate typechecks and executes the published artifact with Bun `1.4.0`.
65
-
66
- The repository-validated and supported minimum compiler/lib contract uses `target: 'ES2022'` with `lib: ['ES2022', 'ESNext.Disposable', 'DOM', 'DOM.Iterable']`. The gate is pinned to TypeScript 7; older compiler versions are not promised. This supported set is verified together rather than claiming that every entry is independently forced by one declaration, and it supplies types only — not runtime Web API polyfills.
67
-
68
- **SSE reconnect behavior change:** without `withSSEReconnect(...)`, SSE no longer retries network/stream-read failures. Pass `withSSEReconnect({ attempts: 3 })` (or another reviewed budget) to retry those failures.
38
+ async function main() {
39
+ const [error, user] = await getUser(client, { id: 1 });
40
+ if (error) {
41
+ console.error(String(error), error.code);
42
+ return;
43
+ }
44
+ console.log(user.name);
45
+ }
69
46
 
70
- When using a checkout through `file:` or a workspace link, run `bun run build` in the checkout before compiling or running the external consumer. The checkout manifest points to generated `dist/` files; published packages already contain those files.
47
+ void main();
48
+ ```
71
49
 
72
- After compiling an application to ESM, the repository-tested command is:
50
+ Calling `getUser(client, { id: 1 })` validates, builds, and sends the request. `client({ abort })` derives a new client for one call and does not perform I/O. Return before reading the success value when `error` is set. Once published, import `getUser` from your SDK package instead of the local file — see [Build and publish an SDK](https://defjs.lyz.cloud/recipes/publish-http-sdk).
73
51
 
74
- ```sh
75
- bun run dist/index.js
76
- ```
52
+ ## Rules that matter
77
53
 
78
- Browser applications use their bundler and the platform Fetch stream and WebSocket capabilities required by the transports they enable.
54
+ - Calling an operation with a client performs I/O. A definition does not capture a client. There is no global client.
55
+ - Per-call options are the seven `RequestOptions` fields: `abort`, `onUploadProgress`, `onDownloadProgress`, `beforeConnect`, `protocols`, `heartbeat`, and `reconnect`. `client(options)` copies those fields into a fresh object. Nested `heartbeat`, `protocols`, and `reconnect` values are kept by reference, so treat them as immutable after passing them. Pass `AbortSignal.timeout(ms)` as `abort` when a call needs a deadline. That reason is `NET_TIMEOUT`; a manual abort is `NET_ABORTED`. A getter that throws does so from `client(options)`, not as a fault. SSE and WebSocket have no startup-only deadline: the signal aborts the whole connection.
56
+ - `input` declares parameters; a synchronous, pure `builder` places them on `path`, `query`, `headers`, and `body`. Every definition with `input` requires an explicit `builder`.
57
+ - Structs validate at runtime. `output` is the 2xx body, `error` every other status; omit a side and that body is never read.
58
+ - Failures are returned as `Fault` instances in an error-first tuple — `HTTP_STATUS`, `REQ_*`, `NET_*`, `RES_*`, `EXT_*`, `CAP_*`, `ENV_UNSUPPORTED`. `String(error)` gives the message; `error.code` and the cause chain stay structured for logs.
59
+ - A timeout or cancellation does not prove the server missed a write. Keep an application idempotency contract before replaying writes.
60
+ - Returned SSE and WebSocket handles are `AsyncDisposable`; WebSocket `closed` is the logical terminal result.
61
+ - Inject a Fetch-compatible function with `withHTTPHandle(...)` to test a client without a server — see [Test with a handle](https://defjs.lyz.cloud/recipes/test-with-handle).
79
62
 
80
63
  ## Documentation
81
64
 
82
- Guides live on the documentation site, not in the published tarball.
65
+ - [Getting started](https://defjs.lyz.cloud/docs/start)
66
+ - [Client](https://defjs.lyz.cloud/docs/client) · [Errors](https://defjs.lyz.cloud/docs/errors) · [Struct](https://defjs.lyz.cloud/docs/struct)
67
+ - [HTTP](https://defjs.lyz.cloud/docs/http) · [SSE](https://defjs.lyz.cloud/docs/sse) · [WebSocket](https://defjs.lyz.cloud/docs/web-socket)
68
+
69
+ ## License
83
70
 
84
- - [Getting started](https://defjs.org/guide/getting-started)
85
- - [Client](https://defjs.org/core/client)
86
- - [HTTP](https://defjs.org/core/http)
87
- - [SSE](https://defjs.org/core/sse)
88
- - [WebSocket](https://defjs.org/core/web-socket)
71
+ MIT.