@defjs/core 0.4.0-beta.0 → 0.4.0-beta.1
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.
- package/README.md +10 -47
- package/index.d.ts +487 -435
- package/index.js +5078 -4580
- package/index.min.js +44 -2
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -22,32 +22,30 @@ const client = createClient(withEndpoint('https://api.example.com'))
|
|
|
22
22
|
const getUser = defineRequest({
|
|
23
23
|
method: 'GET',
|
|
24
24
|
path: '/users/:id',
|
|
25
|
-
input: struct.
|
|
25
|
+
input: struct.object({
|
|
26
26
|
path: struct.object({ id: struct.number() }),
|
|
27
27
|
}),
|
|
28
|
-
output:
|
|
29
|
-
|
|
30
|
-
{ status: 404, body: struct.object({ message: struct.string() }) },
|
|
31
|
-
],
|
|
28
|
+
output: struct.object({ id: struct.number(), name: struct.string() }),
|
|
29
|
+
error: struct.object({ message: struct.string() }),
|
|
32
30
|
})
|
|
33
31
|
|
|
34
32
|
const [error, user] = await client.execute(getUser({ path: { id: 1 } }))
|
|
35
33
|
|
|
36
34
|
if (error) {
|
|
37
|
-
console.error(String(error), error.
|
|
35
|
+
console.error(String(error), error.code)
|
|
38
36
|
} else {
|
|
39
37
|
console.log(user.id, user.name)
|
|
40
38
|
}
|
|
41
39
|
```
|
|
42
40
|
|
|
43
|
-
`
|
|
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.
|
|
44
42
|
|
|
45
43
|
## Core Boundaries
|
|
46
44
|
|
|
47
45
|
- Commands are typed values created by `defineRequest`, `defineEventStream`, and `defineWebSocket`.
|
|
48
|
-
- Structs validate request input and response data at runtime. `
|
|
49
|
-
- Expected
|
|
50
|
-
-
|
|
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()`.
|
|
51
49
|
- Server clients that capture cookies, authorization, tenant data, or user data must be created inside the owning request scope.
|
|
52
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.
|
|
53
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.
|
|
@@ -57,44 +55,9 @@ if (error) {
|
|
|
57
55
|
|
|
58
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.
|
|
59
57
|
|
|
60
|
-
### WebSocket
|
|
58
|
+
### WebSocket messages
|
|
61
59
|
|
|
62
|
-
`
|
|
63
|
-
|
|
64
|
-
```typescript
|
|
65
|
-
const kraken = defineWebSocket({
|
|
66
|
-
incoming: {
|
|
67
|
-
'method.subscribe': struct.object({ method: struct.literal('subscribe'), success: struct.boolean() }),
|
|
68
|
-
},
|
|
69
|
-
maxIncomingQueueSize: 16,
|
|
70
|
-
normalizeIncoming(decoded) {
|
|
71
|
-
if (typeof decoded !== 'object' || decoded === null || Array.isArray(decoded)) return undefined
|
|
72
|
-
if (Reflect.get(decoded, 'method') !== 'subscribe') return undefined
|
|
73
|
-
return { data: decoded, type: 'method.subscribe' }
|
|
74
|
-
},
|
|
75
|
-
normalizeOutgoing(_type, encodedPayload) {
|
|
76
|
-
if (typeof encodedPayload !== 'object' || encodedPayload === null || Array.isArray(encodedPayload)) {
|
|
77
|
-
throw new TypeError('Expected encoded command')
|
|
78
|
-
}
|
|
79
|
-
return encodedPayload as { readonly [key: string]: unknown }
|
|
80
|
-
},
|
|
81
|
-
outgoing: {
|
|
82
|
-
subscribe: struct.object({
|
|
83
|
-
method: struct.literal('subscribe'),
|
|
84
|
-
params: struct.object({ channel: struct.string() }),
|
|
85
|
-
reqId: struct.number().alias('req_id'),
|
|
86
|
-
}),
|
|
87
|
-
},
|
|
88
|
-
path: '/v2',
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
// session.send({ type: 'subscribe', method: 'subscribe', params: { channel: 'ticker' }, reqId: 1 })
|
|
92
|
-
// wire: {"method":"subscribe","params":{"channel":"ticker"},"req_id":1}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
Both adapters are synchronous. An outgoing adapter exception escapes `session.send()` synchronously; heartbeat serialization uses the existing fatal runtime path. Reconnect queues retain the already-normalized serialized string. If a provider payload itself has a wire `type`, declare it under a non-dispatch property such as `providerType: struct.literal('update').alias('type')`.
|
|
96
|
-
|
|
97
|
-
The adapters do not replace Struct validation, WebSocket subprotocols, reconnect policy, or session lifecycle. Without them, incoming results and outgoing bytes keep the legacy Defjs envelope behavior.
|
|
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`.
|
|
98
61
|
|
|
99
62
|
## Runtime Notes
|
|
100
63
|
|