@aventara/next 1.0.0-rc.10 → 1.0.0-rc.12
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/CHANGELOG.md +61 -0
- package/README.md +30 -0
- package/dist/aventara.factory.d.ts +5 -0
- package/dist/protocol-route.table.d.ts +5 -1
- package/dist/protocol-route.table.js +3 -0
- package/dist/request-state.cache.d.ts +3 -3
- package/dist/request-state.cache.js +6 -1
- package/dist/route-handlers.factory.js +1 -1
- package/dist/server-operations.factory.js +10 -1
- package/dist/universal-path.registry.d.ts +2 -2
- package/dist/universal-path.registry.js +23 -4
- package/dist/web-exchange.translator.d.ts +12 -4
- package/dist/web-exchange.translator.js +24 -0
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,66 @@
|
|
|
1
1
|
# @aventara/next
|
|
2
2
|
|
|
3
|
+
## 1.0.0-rc.12
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [fdeee8a]
|
|
8
|
+
- @aventara/core@1.0.0-rc.12
|
|
9
|
+
- @aventara/mcp@1.0.0-rc.12
|
|
10
|
+
|
|
11
|
+
## 1.0.0-rc.11
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- 6197c08: `@/aventara/universal`'s calls are the generated client's own calls again. The entry no longer wraps each one in
|
|
16
|
+
`io().then(call)`, so its own `signal`, `avClient.all`'s `signal` and strict abort, and `avLazy` all reach it, in the
|
|
17
|
+
browser and on the server. Next's `io()` is now awaited before the request is sent.
|
|
18
|
+
|
|
19
|
+
In the browser, the calls made in one tick are still grouped into one `/_all`. On the server, none is grouped: each
|
|
20
|
+
call has a client of its own with grouping off, and it is sent from the async context of the code that made it. Before,
|
|
21
|
+
one queue served every request. Calls from two concurrent requests, or a call inside `unstable_cache` and one outside
|
|
22
|
+
it, could share a flush and run with the first call's headers and `state`.
|
|
23
|
+
|
|
24
|
+
`avLazy` no longer keeps one answer for every request on a server:
|
|
25
|
+
|
|
26
|
+
- The generated client's `avLazy` keeps its answer in a page. On a server (no `location`) it keeps none, and each await
|
|
27
|
+
makes the call again.
|
|
28
|
+
- `@aventara/core`'s `avLazy` keeps none: each await makes the call again.
|
|
29
|
+
- `@/aventara/universal` now exports its own `avLazy`, which keeps one answer per request inside a React render
|
|
30
|
+
(React's `cache`, which the entry now imports) and none where React keeps no request.
|
|
31
|
+
|
|
32
|
+
Before, an `avLazy` made at module scope handed the first request's answer to every request after it.
|
|
33
|
+
|
|
34
|
+
`ready()`'s in-process path now splits a cached read's GET URL into its path and its `?q=&v=` query, with an empty
|
|
35
|
+
body, so the read reaches its GET route instead of being answered as absent.
|
|
36
|
+
|
|
37
|
+
- e0e89c1: `POST {api}/_all` now streams when the client asks for it: the hosts forward `Accept`, so with
|
|
38
|
+
`application/x-ndjson` each entry's line is written as it settles (Nest on Express and Fastify writes it to the response,
|
|
39
|
+
flushed through `compression` when present; Next returns a `ReadableStream`), and plain JSON stays the answer otherwise.
|
|
40
|
+
When the client disconnects, the set stops: entries not yet started never start.
|
|
41
|
+
- 186bc29: `POST {api}/_all` is mounted with the other protocol routes and answered by the binding's `handleAll`.
|
|
42
|
+
- 33b5f83: The hosts hand the request URL's query to the protocol, so a cached read's `GET` (a read with a `cache({ for, maxAge })` stage)
|
|
43
|
+
is mounted and answered like every other route in `protocol.surface()`, on Express, Fastify and Next.js.
|
|
44
|
+
- 11ece49: `avClient.all(entries, { settle?, signal? })` is the Framework's `serverClient.all` with this request's state, so a
|
|
45
|
+
Server Component, Route Handler or Server Action writes it as a browser component writes the generated client's
|
|
46
|
+
`avClient.all`. `avClient` calls still run when made and now take their own `signal`; wrap one in `avLazy(() => …)`
|
|
47
|
+
(`@aventara/core`) for `all` to start it under `limits.maxAllConcurrency`.
|
|
48
|
+
- a05d970: Every `avClient` call of one render is checked as the same principal. The state `state` seeds once per render is
|
|
49
|
+
held as that request's, so the principal is derived once, before any stage runs. A stage in one call that writes
|
|
50
|
+
`ctx.$state` no longer changes who a later or concurrent call of the same render, an `avClient.transaction`, or a
|
|
51
|
+
server-side `@/aventara/universal` call is checked as.
|
|
52
|
+
- Updated dependencies [6197c08]
|
|
53
|
+
- Updated dependencies [e0e89c1]
|
|
54
|
+
- Updated dependencies [186bc29]
|
|
55
|
+
- Updated dependencies [33b5f83]
|
|
56
|
+
- Updated dependencies [6d8b589]
|
|
57
|
+
- Updated dependencies [11ece49]
|
|
58
|
+
- Updated dependencies [92fd093]
|
|
59
|
+
- Updated dependencies [e5e98e6]
|
|
60
|
+
- Updated dependencies [a05d970]
|
|
61
|
+
- @aventara/core@1.0.0-rc.11
|
|
62
|
+
- @aventara/mcp@1.0.0-rc.11
|
|
63
|
+
|
|
3
64
|
## 1.0.0-rc.10
|
|
4
65
|
|
|
5
66
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -102,6 +102,27 @@ Contract's view (what the client layer hides is absent), taking and answering ap
|
|
|
102
102
|
policy as a request to `handlers`, with the principal `policy.principal` reads from `state`. A refusal is thrown as
|
|
103
103
|
its `AvError` class (`AvAuthError` for the policy).
|
|
104
104
|
|
|
105
|
+
`avClient.all({ key: call, … }, { settle?, signal? })` awaits an object of calls together, in process, as the
|
|
106
|
+
generated client's `avClient.all` does in the browser, so a component reads alike on both sides:
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import { avLazy } from "@aventara/core";
|
|
110
|
+
|
|
111
|
+
const { campaigns, count } = await avClient.all({
|
|
112
|
+
campaigns: avClient.Campaign.find.many({ select: ["id", "name"] }),
|
|
113
|
+
count: avLazy(() => avClient.Campaign.find.count({})),
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
A call runs when it is made, so `all` cannot pace it. Wrap a call in `avLazy(() => …)` to have `all` start it: at
|
|
118
|
+
most `limits.maxAllConcurrency` at once, and never once `all` has failed or been aborted. `@aventara/core`'s `avLazy`
|
|
119
|
+
keeps no answer: each await makes the call again, so one made at module scope never hands one request's answer to
|
|
120
|
+
another. It takes any number of
|
|
121
|
+
entries: `limits.maxAll` bounds `POST /_all` only. Strict by default: the first
|
|
122
|
+
failure rejects it (fail-fast, not atomic). With `settle: true` each key is `{ status: "fulfilled", value }` or
|
|
123
|
+
`{ status: "rejected", reason }`. Its `signal` aborts each entry; a call's own `signal` (`{ signal }` in its options)
|
|
124
|
+
aborts only that call. Nothing is aborted for you. A Resource named `all` is refused when the Framework is built.
|
|
125
|
+
|
|
105
126
|
`state` is called with `{ headers }` from `next/headers` (there is no `request` outside a route call), once per
|
|
106
127
|
server render however many calls the render makes. Outside a render, in a Server Action's body for example, it runs
|
|
107
128
|
once per call. A call that names its own `state` in its options uses it as given. Without a `state` option, calls
|
|
@@ -197,6 +218,15 @@ both sides: in the browser it calls `/api`; on the server it answers the same re
|
|
|
197
218
|
protocol and with this request's `state`, so a query prefetched in a Server Component and refetched in the browser
|
|
198
219
|
gets the same values (`Date`, `bigint`, the client's own `AvDecimal`).
|
|
199
220
|
|
|
221
|
+
Its calls are the generated client's own on both sides: made when written, aborted by their own `signal`, and reached
|
|
222
|
+
by `avClient.all`'s `signal` and strict abort and by `avLazy`. In the browser the calls made in one tick are grouped
|
|
223
|
+
into one `/_all`. On the server none is grouped: each call is sent on its own, from the async context of the code that
|
|
224
|
+
made it (its request, `unstable_cache`'s scope, your own), so it runs with that scope's `state`; in process a group
|
|
225
|
+
would save no round trip. It exports `avLazy` beside `avClient`, for components that run on both sides. In the
|
|
226
|
+
browser an `avLazy` makes its call once and keeps the answer. On the server it keeps one answer per request inside a
|
|
227
|
+
render (React's `cache`), and none where React keeps no request, such as a route handler or a Server Action, where each
|
|
228
|
+
await makes the call again.
|
|
229
|
+
|
|
200
230
|
A decimal is a class instance, which React refuses to pass from a Server Component to a Client Component. `avDehydrate`
|
|
201
231
|
(this package, server side) turns each `Date`, `bigint`, `Uint8Array` and decimal into a tagged plain object, and
|
|
202
232
|
`avHydrate` (`@/aventara/client`, browser side) turns them back.
|
|
@@ -85,6 +85,11 @@ type AventaraHostOf<F extends HostedMembers> = {
|
|
|
85
85
|
*
|
|
86
86
|
* `avClient.tx` builds client-layer transaction handles and
|
|
87
87
|
* `avClient.transaction([...])` runs them with the same state.
|
|
88
|
+
*
|
|
89
|
+
* `avClient.all({ … }, { settle?, signal? })` awaits an object of calls
|
|
90
|
+
* together, in process, as the generated client's `avClient.all` does in the
|
|
91
|
+
* browser; `avLazy(() => call)` entries (`@aventara/core`) it starts itself,
|
|
92
|
+
* at most `limits.maxAllConcurrency` at once.
|
|
88
93
|
*/
|
|
89
94
|
readonly avClient: F["serverClient"] & {
|
|
90
95
|
/**
|
|
@@ -5,8 +5,12 @@ import type { McpBinding, McpRequest, McpRoute } from "./mcp-binding.loader.js";
|
|
|
5
5
|
type SurfaceRoute = ReturnType<AvProtocolBinding["surface"]>[number];
|
|
6
6
|
/** The developer's `state` option over one route request: seeds its `ctx.$state`. */
|
|
7
7
|
export type StateSeed = () => AvState | Promise<AvState>;
|
|
8
|
+
/** An answer a route writes: the protocol's, its body text or, for a streamed `/_all`, lines as they settle. */
|
|
9
|
+
export type RouteResponse = Awaited<ReturnType<AvProtocolBinding["handleAll"]>>;
|
|
8
10
|
/** What a route answers its request with: a bound protocol member. */
|
|
9
|
-
export type RouteAnswer = (request: AvProtocolRequest, state: StateSeed | undefined
|
|
11
|
+
export type RouteAnswer = (request: AvProtocolRequest, state: StateSeed | undefined,
|
|
12
|
+
/** Aborted when the client goes away (`request.signal`); only `/_all` reads it. */
|
|
13
|
+
disconnect: AbortSignal) => RouteResponse | Promise<RouteResponse>;
|
|
10
14
|
/** The bound member each kind of surface route is answered by. */
|
|
11
15
|
type ProtocolRouteTable = {
|
|
12
16
|
readonly [K in SurfaceRoute["kind"]]: (binding: AvProtocolBinding) => RouteAnswer;
|
|
@@ -3,6 +3,9 @@ export const PROTOCOL_ROUTES = {
|
|
|
3
3
|
contract: (binding) => (request) => binding.encodeContract(request),
|
|
4
4
|
transactions: (binding) => (request, state) => binding.handleTransaction(request, state === undefined ? {} : { state }),
|
|
5
5
|
can: (binding) => (request, state) => binding.handleCan(request, state === undefined ? {} : { state }),
|
|
6
|
+
all: (binding) => (request, state, disconnect) => binding.handleAll(request, state === undefined
|
|
7
|
+
? { signal: disconnect }
|
|
8
|
+
: { state, signal: disconnect }),
|
|
6
9
|
};
|
|
7
10
|
export const MCP_ROUTES = {
|
|
8
11
|
endpoint: (binding) => (request, state) => binding.handleEndpoint(request, state === undefined ? {} : { state }),
|
|
@@ -2,8 +2,8 @@ import type { AvState } from "@aventara/core";
|
|
|
2
2
|
import type { HostState } from "./route-handlers.factory.js";
|
|
3
3
|
/**
|
|
4
4
|
* The request's state for `avClient`: the developer's `state`, handed the
|
|
5
|
-
* headers `next/headers` reads, run once per request
|
|
6
|
-
*
|
|
7
|
-
* headers.
|
|
5
|
+
* headers `next/headers` reads, run once per request, its principal derived
|
|
6
|
+
* once for the request. `undefined` without a `state` option, so the call
|
|
7
|
+
* starts from `{}` as on a route, and reads no headers.
|
|
8
8
|
*/
|
|
9
9
|
export declare function createRequestState(state: HostState | undefined): () => Promise<AvState | undefined>;
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
+
import { holdRequestPrincipal } from "@aventara/core/internal";
|
|
1
2
|
import { headers } from "next/headers.js";
|
|
2
3
|
import { cache } from "react";
|
|
3
4
|
export function createRequestState(state) {
|
|
4
5
|
if (state === undefined) {
|
|
5
6
|
return async () => undefined;
|
|
6
7
|
}
|
|
7
|
-
return cache(async () =>
|
|
8
|
+
return cache(async () => {
|
|
9
|
+
const seeded = await state({ headers: await headers() });
|
|
10
|
+
holdRequestPrincipal(seeded);
|
|
11
|
+
return seeded;
|
|
12
|
+
});
|
|
8
13
|
}
|
|
@@ -57,7 +57,7 @@ export function createRouteHandlers(host, state) {
|
|
|
57
57
|
if (body.kind !== "read") {
|
|
58
58
|
return webResponse(unreadBodyAnswer(binding, body));
|
|
59
59
|
}
|
|
60
|
-
return webResponse(await answer(protocolRequest(request, path, body.content), seed));
|
|
60
|
+
return webResponse(await answer(protocolRequest(request, path, body.content), seed, request.signal));
|
|
61
61
|
};
|
|
62
62
|
return Object.freeze({
|
|
63
63
|
GET: handle,
|
|
@@ -11,7 +11,7 @@ function ioBeforeCall() {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
const handlesBeforeBuild = (member) => `Aventara: \`${member}\` builds its handles on the Framework, which is built on first use; \`await ready()\` before building them.`;
|
|
14
|
-
const CLIENT_MEMBERS = ["tx", "transaction", "$access"];
|
|
14
|
+
const CLIENT_MEMBERS = ["all", "tx", "transaction", "$access"];
|
|
15
15
|
const APPLICATION_MEMBERS = ["appTx", "transaction"];
|
|
16
16
|
export function refuseMemberClashes(framework) {
|
|
17
17
|
const clashes = [
|
|
@@ -41,10 +41,12 @@ export function createServerOperations(source, requestState, access) {
|
|
|
41
41
|
};
|
|
42
42
|
const asGiven = async (options) => options;
|
|
43
43
|
const clientTransaction = transactionOf(source, withRequestState);
|
|
44
|
+
const all = allOf(source);
|
|
44
45
|
const applicationTransaction = transactionOf(source, asGiven);
|
|
45
46
|
const verbs = accessOf(source, withRequestState, access);
|
|
46
47
|
return {
|
|
47
48
|
avClient: operationTree("avClient", source, (framework) => framework.serverClient, withRequestState, {
|
|
49
|
+
all: () => all,
|
|
48
50
|
tx: () => builders(source, "avClient.tx").serverClientTx,
|
|
49
51
|
transaction: () => clientTransaction,
|
|
50
52
|
$access: () => verbs,
|
|
@@ -125,6 +127,13 @@ function transactionOf(source, fill) {
|
|
|
125
127
|
};
|
|
126
128
|
}
|
|
127
129
|
const NEVER_A_RESOURCE = new Set(["then", "__esModule"]);
|
|
130
|
+
function allOf(source) {
|
|
131
|
+
return async (entries, options) => {
|
|
132
|
+
await ioBeforeCall();
|
|
133
|
+
const framework = await source.built();
|
|
134
|
+
return framework.serverClient.all(entries, options);
|
|
135
|
+
};
|
|
136
|
+
}
|
|
128
137
|
function operationTree(name, source, layer, fill, members) {
|
|
129
138
|
const leaf = (path) => async (args, options) => {
|
|
130
139
|
await ioBeforeCall();
|
|
@@ -2,11 +2,11 @@ import type { StateSeed } from "./protocol-route.table.js";
|
|
|
2
2
|
import { type ProtocolHost } from "./route-handlers.factory.js";
|
|
3
3
|
/** The `globalThis` key the in-process path is registered under. */
|
|
4
4
|
export declare const UNIVERSAL_PATH_KEY: unique symbol;
|
|
5
|
-
/** The request the generated client's transport hands to its `fetch
|
|
5
|
+
/** The request the generated client's transport hands to its `fetch`: a cached read's GET has no body. */
|
|
6
6
|
export type UniversalRequest = {
|
|
7
7
|
readonly method: string;
|
|
8
8
|
readonly headers: Readonly<Record<string, string>>;
|
|
9
|
-
readonly body
|
|
9
|
+
readonly body?: string;
|
|
10
10
|
};
|
|
11
11
|
/** What the generated client's transport reads of a `fetch` answer. */
|
|
12
12
|
export type UniversalAnswer = {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { routeKey } from "./route-handlers.factory.js";
|
|
2
2
|
export const UNIVERSAL_PATH_KEY = Symbol.for("aventara.next.universal");
|
|
3
|
+
const IN_PROCESS = new AbortController().signal;
|
|
3
4
|
function outsideApi(url, api) {
|
|
4
5
|
return `Aventara: @/aventara/universal called ${url} on the server, which is not under the configured \`api\` path ${api === "" ? "/" : api}; run aventara-build --client again (npm run aventara:prepare).`;
|
|
5
6
|
}
|
|
@@ -9,23 +10,41 @@ export function universalPath(host, state) {
|
|
|
9
10
|
if (url !== api && !url.startsWith(`${api}/`)) {
|
|
10
11
|
throw new Error(outsideApi(url, api));
|
|
11
12
|
}
|
|
12
|
-
const path = url.slice(api.length);
|
|
13
|
+
const [path = "", query] = splitQuery(url.slice(api.length));
|
|
13
14
|
const request = {
|
|
14
15
|
method: init.method,
|
|
15
16
|
path,
|
|
17
|
+
...(query === undefined ? {} : { query }),
|
|
16
18
|
headers: Object.fromEntries(new Headers(init.headers)),
|
|
17
|
-
body: { kind: "raw", content: init.body },
|
|
19
|
+
body: { kind: "raw", content: init.body ?? "" },
|
|
18
20
|
};
|
|
19
21
|
const answer = routes.get(routeKey(init.method, path));
|
|
20
22
|
const response = answer === undefined
|
|
21
23
|
? binding.answerAbsent(request)
|
|
22
|
-
: await answer(request, state);
|
|
24
|
+
: await answer(request, state, IN_PROCESS);
|
|
23
25
|
if (response === undefined) {
|
|
24
26
|
throw new Error(outsideApi(url, api));
|
|
25
27
|
}
|
|
26
|
-
|
|
28
|
+
const { body } = response;
|
|
29
|
+
return {
|
|
30
|
+
status: response.status,
|
|
31
|
+
text: async () => (typeof body === "string" ? body : await joined(body)),
|
|
32
|
+
};
|
|
27
33
|
};
|
|
28
34
|
}
|
|
35
|
+
function splitQuery(url) {
|
|
36
|
+
const mark = url.indexOf("?");
|
|
37
|
+
return mark === -1
|
|
38
|
+
? [url, undefined]
|
|
39
|
+
: [url.slice(0, mark), url.slice(mark + 1)];
|
|
40
|
+
}
|
|
41
|
+
async function joined(lines) {
|
|
42
|
+
let text = "";
|
|
43
|
+
for await (const line of lines) {
|
|
44
|
+
text += line;
|
|
45
|
+
}
|
|
46
|
+
return text;
|
|
47
|
+
}
|
|
29
48
|
const UNIVERSAL_ACCESS_KEY = Symbol.for("aventara.next.universal.access");
|
|
30
49
|
export function registerUniversalPath(path, access) {
|
|
31
50
|
const holder = globalThis;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { AvProtocolRequest
|
|
1
|
+
import type { AvProtocolRequest } from "@aventara/core/protocol";
|
|
2
2
|
import type { McpRequest } from "./mcp-binding.loader.js";
|
|
3
|
+
import type { RouteResponse } from "./protocol-route.table.js";
|
|
3
4
|
/** Zero bytes: the body of a request whose body the protocol does not read. */
|
|
4
5
|
export declare const NO_BYTES: Uint8Array<ArrayBuffer>;
|
|
5
6
|
/**
|
|
@@ -7,9 +8,16 @@ export declare const NO_BYTES: Uint8Array<ArrayBuffer>;
|
|
|
7
8
|
* nothing URL-decoded.
|
|
8
9
|
*/
|
|
9
10
|
export declare function pathnameOf(request: Request): string;
|
|
10
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* The request as the protocol reads it: path relative to the mount path, raw
|
|
13
|
+
* query (rc.11: a cached read's `q` and `v`), its headers, raw body.
|
|
14
|
+
*/
|
|
11
15
|
export declare function protocolRequest(request: Request, path: string, content: Uint8Array): AvProtocolRequest;
|
|
12
16
|
/** The request as `@aventara/mcp` reads it: absolute URL at the origin the caller used, its headers, raw body, no peer address. */
|
|
13
17
|
export declare function mcpRequest(request: Request, content: Uint8Array): McpRequest;
|
|
14
|
-
/**
|
|
15
|
-
|
|
18
|
+
/**
|
|
19
|
+
* The protocol's answer as the route handler's `Response`: status, headers and
|
|
20
|
+
* body as they are. A streamed body (`/_all` under NDJSON) is a
|
|
21
|
+
* `ReadableStream` that pulls each line as core yields it.
|
|
22
|
+
*/
|
|
23
|
+
export declare function webResponse(answer: RouteResponse): Response;
|
|
@@ -6,6 +6,7 @@ export function protocolRequest(request, path, content) {
|
|
|
6
6
|
return {
|
|
7
7
|
method: request.method,
|
|
8
8
|
path,
|
|
9
|
+
query: new URL(request.url).search.slice(1),
|
|
9
10
|
headers: Object.fromEntries(request.headers),
|
|
10
11
|
body: { kind: "raw", content },
|
|
11
12
|
};
|
|
@@ -30,8 +31,31 @@ function calledUrl(request) {
|
|
|
30
31
|
return `${scheme ?? url.protocol.slice(0, -1)}://${host ?? url.host}${url.pathname}${url.search}`;
|
|
31
32
|
}
|
|
32
33
|
export function webResponse(answer) {
|
|
34
|
+
if (typeof answer.body !== "string") {
|
|
35
|
+
return new Response(streamOf(answer.body), {
|
|
36
|
+
status: answer.status,
|
|
37
|
+
headers: answer.headers,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
33
40
|
return new Response(answer.body === "" ? null : answer.body, {
|
|
34
41
|
status: answer.status,
|
|
35
42
|
headers: answer.headers,
|
|
36
43
|
});
|
|
37
44
|
}
|
|
45
|
+
function streamOf(lines) {
|
|
46
|
+
const iterator = lines[Symbol.asyncIterator]();
|
|
47
|
+
const encoder = new TextEncoder();
|
|
48
|
+
return new ReadableStream({
|
|
49
|
+
async pull(controller) {
|
|
50
|
+
const next = await iterator.next();
|
|
51
|
+
if (next.done === true) {
|
|
52
|
+
controller.close();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
controller.enqueue(encoder.encode(next.value));
|
|
56
|
+
},
|
|
57
|
+
async cancel() {
|
|
58
|
+
await iterator.return?.();
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aventara/next",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.12",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"description": "Next.js App Router host integration for Aventara.",
|
|
6
6
|
"type": "module",
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
"CHANGELOG.md"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@aventara/core": "1.0.0-rc.
|
|
25
|
+
"@aventara/core": "1.0.0-rc.12",
|
|
26
26
|
"server-only": "0.0.1"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
29
|
-
"@aventara/mcp": "1.0.0-rc.
|
|
29
|
+
"@aventara/mcp": "1.0.0-rc.12",
|
|
30
30
|
"next": ">=16.4 <17",
|
|
31
31
|
"react": "^19.0.0"
|
|
32
32
|
},
|
|
@@ -53,10 +53,10 @@
|
|
|
53
53
|
"access": "public"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@aventara/build": "1.0.0-rc.
|
|
57
|
-
"@aventara/client": "1.0.0-rc.
|
|
58
|
-
"@aventara/mcp": "1.0.0-rc.
|
|
59
|
-
"@aventara/testing": "1.0.0-rc.
|
|
56
|
+
"@aventara/build": "1.0.0-rc.12",
|
|
57
|
+
"@aventara/client": "1.0.0-rc.12",
|
|
58
|
+
"@aventara/mcp": "1.0.0-rc.12",
|
|
59
|
+
"@aventara/testing": "1.0.0-rc.12",
|
|
60
60
|
"@modelcontextprotocol/sdk": "1.32.2",
|
|
61
61
|
"@tanstack/react-query": "5.104.2",
|
|
62
62
|
"@types/react": "19.3.0",
|