@nxara/olio-client 0.0.0-stage → 0.1.0-rc.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/LICENSE +21 -0
- package/README.md +280 -2
- package/dist/document.d.ts +7 -0
- package/dist/document.d.ts.map +1 -0
- package/dist/document.js +79 -0
- package/dist/document.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -0
- package/dist/sse.d.ts +9 -0
- package/dist/sse.d.ts.map +1 -0
- package/dist/sse.js +31 -0
- package/dist/sse.js.map +1 -0
- package/dist/test.d.ts +15 -0
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +88 -0
- package/dist/test.js.map +1 -0
- package/dist/transport.d.ts +17 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +52 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +88 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ws.d.ts +9 -0
- package/dist/ws.d.ts.map +1 -0
- package/dist/ws.js +60 -0
- package/dist/ws.js.map +1 -0
- package/package.json +52 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nxara contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,281 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @nxara/olio-client
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A typed GraphQL client for Nxara apps. You write operations in `.graphql` files; codegen turns them into typed documents, the way graphql-codegen does; the client gives you one call per operation:
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
const { data } = await client.mutation.login({ email, password }, { headers });
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
bun add @nxara/olio-client
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`graphql` 16 is a peer dependency. For subscriptions, add [graphql-ws](https://github.com/enisdenjo/graphql-ws) and/or [graphql-sse](https://github.com/enisdenjo/graphql-sse): the client takes your own clients of them.
|
|
14
|
+
|
|
15
|
+
## Operations
|
|
16
|
+
|
|
17
|
+
```graphql
|
|
18
|
+
# src/operations/auth.graphql
|
|
19
|
+
mutation Login($email: String!, $password: String!) {
|
|
20
|
+
login(email: $email, password: $password) {
|
|
21
|
+
__typename
|
|
22
|
+
... on Session {
|
|
23
|
+
token
|
|
24
|
+
}
|
|
25
|
+
... on UserError {
|
|
26
|
+
message
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Codegen
|
|
33
|
+
|
|
34
|
+
`codegenClient` reads the schema (a file, or the running server's URL by introspection) and the operations, checks the operations against the schema (errors point at `file:line:column`), and writes the types:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { codegenClient } from "@nxara/olio-codegen";
|
|
38
|
+
|
|
39
|
+
await codegenClient({
|
|
40
|
+
schema: "../server/src/schema.gql", // or "http://localhost:4000/graphql"
|
|
41
|
+
documents: "src/operations/*.graphql",
|
|
42
|
+
output: "src/generated.ts",
|
|
43
|
+
headers: { authorization: "Bearer …" } // only for a URL that needs it
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Per operation, named the way graphql-codegen names them: `LoginMutation` (the result), `LoginMutationVariables` and `LoginDocument`. Plus `operations`, every document by root and name, which the client takes.
|
|
48
|
+
|
|
49
|
+
## Calls
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import { createClient } from "@nxara/olio-client";
|
|
53
|
+
|
|
54
|
+
import { operations } from "./generated.js";
|
|
55
|
+
|
|
56
|
+
const client = createClient(operations, {
|
|
57
|
+
url: "https://erp.example/graphql",
|
|
58
|
+
// Nothing before sign-in: an `undefined` value is left out, not sent as text.
|
|
59
|
+
headers: () => ({ authorization: token && `Bearer ${token}` })
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const { data, errors } = await client.mutation.login({ email, password });
|
|
63
|
+
if (data?.login.__typename === "Session") data.login.token;
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
- `client.<query | mutation | subscription>.<operation>(variables?, options?)`. The operation's name with its first letter lowercased: `mutation Login` is `client.mutation.login`.
|
|
67
|
+
- Variables are typed from the operation; they may be left out when none are required.
|
|
68
|
+
- `data` is the operation's result, typed from its selection: fragments narrow on `__typename`, fields under `@include` / `@skip` are optional. `errors` are the GraphQL errors as the server sent them. A response that isn't GraphQL at all (a proxy's 502 page) rejects.
|
|
69
|
+
- `options` takes per-call `headers` and a `signal`.
|
|
70
|
+
- Headers, on the client or per call, are an object, a `Headers`, or entries; in an object, `undefined` values are left out (`token ? { authorization } : {}` works too). The call's win.
|
|
71
|
+
|
|
72
|
+
## Custom fetch
|
|
73
|
+
|
|
74
|
+
`fetch` takes anything fetch-shaped, such as a ky instance:
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import ky from "ky";
|
|
78
|
+
|
|
79
|
+
createClient(operations, { url, fetch: ky.create({ throwHttpErrors: false }) });
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
GraphQL errors can come with 4xx/5xx statuses, so ky needs `throwHttpErrors: false`. A library that isn't fetch-shaped, such as axios, needs a few lines that return a `Response`:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import type { Fetch } from "@nxara/olio-client";
|
|
86
|
+
|
|
87
|
+
const axiosFetch: Fetch = async (url, init) => {
|
|
88
|
+
const res = await axios.request({
|
|
89
|
+
url,
|
|
90
|
+
method: init.method,
|
|
91
|
+
headers: Object.fromEntries(new Headers(init.headers)),
|
|
92
|
+
data: init.body,
|
|
93
|
+
signal: init.signal ?? undefined,
|
|
94
|
+
responseType: "text",
|
|
95
|
+
validateStatus: () => true // GraphQL errors come with 4xx/5xx too
|
|
96
|
+
});
|
|
97
|
+
return new Response(res.data, {
|
|
98
|
+
status: res.status,
|
|
99
|
+
headers: res.headers as Record<string, string>
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`fetch` is for queries and mutations; subscriptions go through your own clients.
|
|
105
|
+
|
|
106
|
+
## Uploading files
|
|
107
|
+
|
|
108
|
+
The client sends JSON, and a `File` in JSON is `{}`. `fetch` also gets the request before JSON, with the variables as you passed them, so it can send them the [multipart request spec](https://github.com/jaydenseric/graphql-multipart-request-spec)'s way instead:
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import type { Fetch } from "@nxara/olio-client";
|
|
112
|
+
|
|
113
|
+
const multipart: Fetch = (url, init, { query, variables, operationName }) => {
|
|
114
|
+
const files = new Map<File, string[]>();
|
|
115
|
+
// Files leave the variables (null in their place); `map` says where each goes back.
|
|
116
|
+
const strip = (value: unknown, path: string): unknown => {
|
|
117
|
+
if (value instanceof File) {
|
|
118
|
+
files.set(value, [...(files.get(value) ?? []), path]);
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
if (Array.isArray(value)) {
|
|
122
|
+
return value.map((v, i) => strip(v, `${path}.${i}`));
|
|
123
|
+
}
|
|
124
|
+
if (value && typeof value === "object") {
|
|
125
|
+
return Object.fromEntries(
|
|
126
|
+
Object.entries(value).map(([k, v]) => [k, strip(v, `${path}.${k}`)])
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
return value;
|
|
130
|
+
};
|
|
131
|
+
const stripped = strip(variables, "variables");
|
|
132
|
+
if (files.size === 0) return fetch(url, init);
|
|
133
|
+
|
|
134
|
+
const form = new FormData();
|
|
135
|
+
form.set(
|
|
136
|
+
"operations",
|
|
137
|
+
JSON.stringify({ query, variables: stripped, operationName })
|
|
138
|
+
);
|
|
139
|
+
form.set(
|
|
140
|
+
"map",
|
|
141
|
+
JSON.stringify(Object.fromEntries([...files.values()].entries()))
|
|
142
|
+
);
|
|
143
|
+
for (const [i, file] of [...files.keys()].entries())
|
|
144
|
+
form.set(String(i), file);
|
|
145
|
+
|
|
146
|
+
const headers = new Headers(init.headers);
|
|
147
|
+
headers.delete("content-type"); // fetch sets it, with the boundary
|
|
148
|
+
headers.set("x-upload", "1"); // browsers can't add it cross-site, so the server can refuse CSRF
|
|
149
|
+
return fetch(url, { ...init, headers, body: form });
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const client = createClient(operations, { url, fetch: multipart });
|
|
153
|
+
await client.mutation.uploadAvatar({ file });
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Register the scalar as `File` (`interface ClientScalars { Upload: File }`). On the server, `@nxara/olio-http` passes graphql-http's `parseRequestParams` through, which puts the files back:
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
fetchHandler(app, {
|
|
160
|
+
context,
|
|
161
|
+
parseRequestParams: async (req) => {
|
|
162
|
+
const request = req.raw as Request;
|
|
163
|
+
if (!request.headers.get("content-type")?.startsWith("multipart/form-data"))
|
|
164
|
+
return; // JSON, as usual
|
|
165
|
+
if (!request.headers.get("x-upload"))
|
|
166
|
+
return new Response(null, { status: 400 });
|
|
167
|
+
const form = await request.formData();
|
|
168
|
+
const params = JSON.parse(String(form.get("operations")));
|
|
169
|
+
const map: Record<string, string[]> = JSON.parse(String(form.get("map")));
|
|
170
|
+
for (const [key, paths] of Object.entries(map)) {
|
|
171
|
+
for (const path of paths) setPath(params, path, form.get(key)); // e.g. lodash's set
|
|
172
|
+
}
|
|
173
|
+
return params;
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
with `scalar Upload` in the SDL, typed `File` in `CustomScalars`. Size limits are the server's (or its proxy's). Many apps skip all this: a mutation returns a signed upload URL, and the browser sends the file straight to storage.
|
|
179
|
+
|
|
180
|
+
## Scalars
|
|
181
|
+
|
|
182
|
+
The way the server's `CustomScalars` works: one type, or `{ input; output }` when variables and results differ. Custom scalars are `unknown` until registered:
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
declare module "@nxara/olio-client" {
|
|
186
|
+
interface ClientScalars {
|
|
187
|
+
DateTime: { input: Date | string; output: string };
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Put it in a `.ts` file, or a `.d.ts` with an `import` or `export {}`.
|
|
193
|
+
|
|
194
|
+
Enums arrive by name (`"CONFIRMED"`), not as the server's internal values.
|
|
195
|
+
|
|
196
|
+
## Subscriptions
|
|
197
|
+
|
|
198
|
+
Over WebSocket by default ([graphql-ws](https://github.com/enisdenjo/graphql-ws)), or as server-sent events on the same URL ([graphql-sse](https://github.com/enisdenjo/graphql-sse)) for an operation marked `@sse`. The choice lives in the operation; the directive is the client's, and codegen removes it from the query the server receives:
|
|
199
|
+
|
|
200
|
+
```graphql
|
|
201
|
+
subscription StockChanged($sku: String) {
|
|
202
|
+
# WebSocket
|
|
203
|
+
stockChanged(sku: $sku) {
|
|
204
|
+
sku
|
|
205
|
+
onHand
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
subscription Notifications @sse {
|
|
210
|
+
# server-sent events
|
|
211
|
+
notifications {
|
|
212
|
+
message
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
for await (const { data } of client.subscription.stockChanged({ sku: "CHAIR-01" })) {
|
|
219
|
+
console.log(data?.stockChanged.onHand);
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
They go through your own [graphql-ws](https://github.com/enisdenjo/graphql-ws) and [graphql-sse](https://github.com/enisdenjo/graphql-sse) clients, which `createClient` requires as `ws` and `sse` once an operation uses that transport (and rejects when none does):
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
import { createClient as createSseClient } from "graphql-sse";
|
|
227
|
+
import { createClient as createWsClient } from "graphql-ws";
|
|
228
|
+
|
|
229
|
+
const headers = () => ({ authorization: token && `Bearer ${token}` });
|
|
230
|
+
const ws = createWsClient({
|
|
231
|
+
url: "wss://erp.example/graphql",
|
|
232
|
+
// Browsers can't set headers on a WebSocket: send them here.
|
|
233
|
+
connectionParams: () => ({ headers: headers() })
|
|
234
|
+
});
|
|
235
|
+
const client = createClient(operations, {
|
|
236
|
+
url: "https://erp.example/graphql",
|
|
237
|
+
headers,
|
|
238
|
+
ws,
|
|
239
|
+
sse: createSseClient({ url: "https://erp.example/graphql", headers })
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
The client calls their `iterate` and types the results; the rest is theirs and yours to configure: connecting, retries, keep-alive. Breaking out of the loop, or aborting `signal`, ends the subscription.
|
|
244
|
+
|
|
245
|
+
- **New credentials:** graphql-ws sends `connectionParams` each time the socket connects. After the token changes, `ws.terminate()` reconnects, and graphql-ws resubscribes live subscriptions on the new socket. It waits out its retry backoff first (`retryWait`, about 1.3 to 4 s by default), and events sent in between are lost. An open SSE stream keeps its headers until you subscribe again.
|
|
246
|
+
- **Refusals:** by default both libraries retry a refused connection for about 40 s before reporting it (graphql-ws on a 4403 close, graphql-sse on any response that isn't 2xx); `retryAttempts: 0` or graphql-ws's `shouldRetry` reports it at once. Then a WebSocket closed with a 4xxx code is an error result (`extensions: { code: "WEBSOCKET_CLOSED", closeCode }`), and graphql-sse throws its `NetworkError` (its `response` holds the status).
|
|
247
|
+
- **Rejected operations** (the server's `onSubscribe` returning errors) are an error result on both, as over HTTP.
|
|
248
|
+
|
|
249
|
+
## Bundle size
|
|
250
|
+
|
|
251
|
+
The client imports neither library: an app bundles only the ones it creates clients with. The client's own code is about 1 KB gzipped.
|
|
252
|
+
|
|
253
|
+
## Tests
|
|
254
|
+
|
|
255
|
+
`testClient` from `@nxara/olio-client/test` is the same client, answered in-process like Hono's `testClient`, through the app's own servers: its fetch handler for queries and mutations, and for subscriptions the graphql-ws options it passes to `useServer` (run over an in-memory socket) and its graphql-sse handler. So tests run production's context, `onConnect`, `onSubscribe`, error masking and cleanup. No server is started:
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
import { testClient } from "@nxara/olio-client/test";
|
|
259
|
+
|
|
260
|
+
// The same objects the server uses.
|
|
261
|
+
import { graphqlHandler } from "../src/http.js";
|
|
262
|
+
import { sseHandler, wsOptions } from "../src/subscriptions.js";
|
|
263
|
+
|
|
264
|
+
const client = testClient(
|
|
265
|
+
operations,
|
|
266
|
+
{ http: graphqlHandler, ws: wsOptions, sse: sseHandler },
|
|
267
|
+
{ headers: { authorization: `Bearer ${token}` } }
|
|
268
|
+
);
|
|
269
|
+
expect((await client.query.me()).data).toEqual({ me: { name: "Mia" } });
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
`ws` and `sse` are required exactly when an operation uses that transport; without subscriptions, the fetch handler alone is enough: `testClient(operations, graphqlHandler)`. Over WebSocket, the headers arrive as `connectionParams: { headers }`, and `ctx.extra` is empty (no socket or request in memory). Its clients never retry, since a failure in memory is final: a refusal over SSE throws at once. It's a separate import, so it never ends up in an app's bundle.
|
|
273
|
+
|
|
274
|
+
## API
|
|
275
|
+
|
|
276
|
+
| | |
|
|
277
|
+
| --- | --- |
|
|
278
|
+
| `createClient(operations, { url, headers?, fetch?, ws?, sse? })` | `headers`: an object, or a function for values that change. `fetch`: default the global one; called with `(url, init, params)`, `params` being the request before JSON (see Uploading files). `ws` / `sse`: your graphql-ws / graphql-sse client, required once an operation uses that transport |
|
|
279
|
+
| `testClient(operations, handler \| { http, ws?, sse? }, { headers?, url? })` | From `@nxara/olio-client/test`: the same client, answered in-process |
|
|
280
|
+
| `ClientScalars` | Augment it with how custom scalars arrive and are sent |
|
|
281
|
+
| `TypedDocument`, `Result`, `Client`, `ClientOptions`, `Operations`, `SubscriptionClient` | The types behind the calls |
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ClientSchema, Operation } from "./types.js";
|
|
2
|
+
export interface Built {
|
|
3
|
+
query: string;
|
|
4
|
+
variables: Record<string, unknown>;
|
|
5
|
+
}
|
|
6
|
+
export declare function buildDocument(schema: ClientSchema, operation: Operation, field: string, args: Record<string, unknown> | undefined, selection: Record<string, unknown> | undefined): Built;
|
|
7
|
+
//# sourceMappingURL=document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAc,SAAS,EAAE,MAAM,YAAY,CAAC;AAEtE,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AA6FD,wBAAgB,aAAa,CAC3B,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EACzC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAC7C,KAAK,CAaP"}
|
package/dist/document.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
2
|
+
class Variables {
|
|
3
|
+
definitions = [];
|
|
4
|
+
values = {};
|
|
5
|
+
add(path, type, value) {
|
|
6
|
+
let name = path.slice(1).join("_").replaceAll(/\W/g, "_");
|
|
7
|
+
while (name in this.values)
|
|
8
|
+
name += "_";
|
|
9
|
+
this.values[name] = value;
|
|
10
|
+
this.definitions.push(`$${name}: ${type}`);
|
|
11
|
+
return `$${name}`;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function argumentsText(schema, vars, where, entry, args, path) {
|
|
15
|
+
const types = Array.isArray(entry) ? entry[1] : undefined;
|
|
16
|
+
if (!types)
|
|
17
|
+
throw new Error(`${where} takes no arguments`);
|
|
18
|
+
const parts = [];
|
|
19
|
+
for (const [name, value] of Object.entries(args)) {
|
|
20
|
+
if (value === undefined)
|
|
21
|
+
continue;
|
|
22
|
+
const type = types[name];
|
|
23
|
+
if (!type)
|
|
24
|
+
throw new Error(`Unknown argument "${name}" on ${where}`);
|
|
25
|
+
parts.push(`${name}: ${vars.add([...path, name], type, value)}`);
|
|
26
|
+
}
|
|
27
|
+
return parts.length ? `(${parts.join(", ")})` : "";
|
|
28
|
+
}
|
|
29
|
+
function selectionText(schema, vars, type, selection, path) {
|
|
30
|
+
const parts = [];
|
|
31
|
+
for (const [key, value] of Object.entries(selection)) {
|
|
32
|
+
if (key === "__args" || key === "__typename" || key === "on")
|
|
33
|
+
continue;
|
|
34
|
+
if (value === false || value === undefined)
|
|
35
|
+
continue;
|
|
36
|
+
parts.push(fieldText(schema, vars, type, key, value, [
|
|
37
|
+
...path,
|
|
38
|
+
key
|
|
39
|
+
]));
|
|
40
|
+
}
|
|
41
|
+
const on = isRecord(selection.on) ? selection.on : undefined;
|
|
42
|
+
for (const [member, sub] of Object.entries(on ?? {})) {
|
|
43
|
+
if (!isRecord(sub))
|
|
44
|
+
continue;
|
|
45
|
+
parts.push(`... on ${member} ${selectionText(schema, vars, member, sub, path)}`);
|
|
46
|
+
}
|
|
47
|
+
if (selection.__typename === true || on)
|
|
48
|
+
parts.unshift("__typename");
|
|
49
|
+
return `{ ${parts.join(" ")} }`;
|
|
50
|
+
}
|
|
51
|
+
function fieldText(schema, vars, parent, key, value, path) {
|
|
52
|
+
const where = `${parent}.${key}`;
|
|
53
|
+
const entry = schema.types[parent]?.[key];
|
|
54
|
+
const args = isRecord(value) && isRecord(value.__args)
|
|
55
|
+
? argumentsText(schema, vars, where, entry, value.__args, path)
|
|
56
|
+
: "";
|
|
57
|
+
const type = typeof entry === "string" ? entry : entry?.[0];
|
|
58
|
+
if (type === undefined || !(type in schema.types))
|
|
59
|
+
return `${key}${args}`;
|
|
60
|
+
if (!isRecord(value))
|
|
61
|
+
throw new Error(`${where} needs a selection of fields`);
|
|
62
|
+
return `${key}${args} ${selectionText(schema, vars, type, value, path)}`;
|
|
63
|
+
}
|
|
64
|
+
export function buildDocument(schema, operation, field, args, selection) {
|
|
65
|
+
const root = schema.roots[operation];
|
|
66
|
+
if (!root)
|
|
67
|
+
throw new Error(`The schema has no ${operation} type`);
|
|
68
|
+
const vars = new Variables();
|
|
69
|
+
const value = args ? { ...selection, __args: args } : (selection ?? true);
|
|
70
|
+
const body = selectionText(schema, vars, root, { [field]: value }, []);
|
|
71
|
+
const definitions = vars.definitions.length
|
|
72
|
+
? `(${vars.definitions.join(", ")})`
|
|
73
|
+
: "";
|
|
74
|
+
return {
|
|
75
|
+
query: `${operation} ${field}${definitions} ${body}`,
|
|
76
|
+
variables: vars.values
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=document.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.js","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Client, ClientOptions, Operations } from "./types.js";
|
|
2
|
+
export type { Fetch, HeadersSource, RequestParams } from "./transport.js";
|
|
3
|
+
export type { CallOptions, Client, ClientOptions, ClientScalars, GraphQLErrorJSON, Operations, Result, Scalar, SubscriptionClient, TypedDocument } from "./types.js";
|
|
4
|
+
export declare function createClient<O extends Operations>(operations: O, options: ClientOptions<O>): Client<O>;
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,MAAM,EACN,aAAa,EACb,UAAU,EAIX,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC1E,YAAY,EACV,WAAW,EACX,MAAM,EACN,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,MAAM,EACN,MAAM,EACN,kBAAkB,EAClB,aAAa,EACd,MAAM,YAAY,CAAC;AAYpB,wBAAgB,YAAY,CAAC,CAAC,SAAS,UAAU,EAC/C,UAAU,EAAE,CAAC,EACb,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,GACxB,MAAM,CAAC,CAAC,CAAC,CA+EX"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { asResult, errorResult, resolveHeaders, stream } from "./transport.js";
|
|
2
|
+
const ACCEPT = "application/graphql-response+json, application/json";
|
|
3
|
+
export function createClient(operations, options) {
|
|
4
|
+
const send = options.fetch ?? ((target, init) => fetch(target, init));
|
|
5
|
+
const subscriptionClients = options;
|
|
6
|
+
const request = async (document, variables, call = {}) => {
|
|
7
|
+
const headers = await resolveHeaders(options.headers, call.headers);
|
|
8
|
+
headers.set("accept", ACCEPT);
|
|
9
|
+
headers.set("content-type", "application/json");
|
|
10
|
+
const params = {
|
|
11
|
+
query: document.query,
|
|
12
|
+
variables,
|
|
13
|
+
operationName: document.name
|
|
14
|
+
};
|
|
15
|
+
const response = await send(String(options.url), {
|
|
16
|
+
method: "POST",
|
|
17
|
+
headers,
|
|
18
|
+
body: JSON.stringify(params),
|
|
19
|
+
signal: call.signal
|
|
20
|
+
}, params);
|
|
21
|
+
if (!response.headers.get("content-type")?.includes("json")) {
|
|
22
|
+
throw new Error(`${document.name}: HTTP ${response.status} ${response.statusText}`.trim());
|
|
23
|
+
}
|
|
24
|
+
return asResult((await response.json()));
|
|
25
|
+
};
|
|
26
|
+
async function* subscribe(document, variables, signal) {
|
|
27
|
+
const kind = document.transport ?? "ws";
|
|
28
|
+
const client = subscriptionClients[kind];
|
|
29
|
+
if (!client) {
|
|
30
|
+
throw new Error(`${document.name} subscribes over ${kind}: pass createClient a graphql-${kind} client as \`${kind}\``);
|
|
31
|
+
}
|
|
32
|
+
const events = client.iterate({
|
|
33
|
+
query: document.query,
|
|
34
|
+
variables: variables,
|
|
35
|
+
operationName: document.name
|
|
36
|
+
});
|
|
37
|
+
try {
|
|
38
|
+
for await (const event of stream(events, signal))
|
|
39
|
+
yield asResult(event);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
const result = errorResult(error);
|
|
43
|
+
if (!result)
|
|
44
|
+
throw error;
|
|
45
|
+
yield result;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return Object.fromEntries(["query", "mutation", "subscription"].map((root) => [
|
|
49
|
+
root,
|
|
50
|
+
Object.fromEntries(Object.entries((operations[root] ?? {})).map(([name, document]) => [
|
|
51
|
+
name,
|
|
52
|
+
(variables, call) => root === "subscription"
|
|
53
|
+
? subscribe(document, variables, call?.signal)
|
|
54
|
+
: request(document, variables, call)
|
|
55
|
+
]))
|
|
56
|
+
]));
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/sse.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ClientOptions } from "graphql-sse";
|
|
2
|
+
import { type Fetch, type HeadersSource, type Transport } from "./transport.js";
|
|
3
|
+
export interface SseOptions extends Omit<ClientOptions<boolean>, "url" | "headers" | "fetchFn"> {
|
|
4
|
+
url?: string | URL;
|
|
5
|
+
headers?: HeadersSource;
|
|
6
|
+
fetch?: Fetch;
|
|
7
|
+
}
|
|
8
|
+
export declare const sse: Transport<SseOptions>;
|
|
9
|
+
//# sourceMappingURL=sse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../src/sse.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5E,OAAO,EAGL,KAAK,KAAK,EACV,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAGxB,MAAM,WAAW,UAAW,SAAQ,IAAI,CACtC,aAAa,CAAC,OAAO,CAAC,EACtB,KAAK,GAAG,SAAS,GAAG,SAAS,CAC9B;IAEC,GAAG,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,OAAO,CAAC,EAAE,aAAa,CAAC;IAExB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAGD,eAAO,MAAM,GAAG,EAAE,SAAS,CAAC,UAAU,CA2BrC,CAAC"}
|
package/dist/sse.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createClient } from "graphql-sse";
|
|
2
|
+
import { asResult, stream } from "./transport.js";
|
|
3
|
+
export const sse = {
|
|
4
|
+
kind: "sse",
|
|
5
|
+
connect(endpoint, options = {}) {
|
|
6
|
+
let client;
|
|
7
|
+
return {
|
|
8
|
+
async *subscribe(document, variables, signal) {
|
|
9
|
+
client ??= createClient({
|
|
10
|
+
...options,
|
|
11
|
+
url: endpoint.url,
|
|
12
|
+
fetchFn: endpoint.fetch,
|
|
13
|
+
headers: async () => Object.fromEntries(await endpoint.headers())
|
|
14
|
+
});
|
|
15
|
+
const events = client.iterate({
|
|
16
|
+
query: document.query,
|
|
17
|
+
variables: variables,
|
|
18
|
+
operationName: document.name
|
|
19
|
+
});
|
|
20
|
+
for await (const event of stream(events, signal))
|
|
21
|
+
yield asResult(event);
|
|
22
|
+
},
|
|
23
|
+
reconnect() { },
|
|
24
|
+
close: async () => {
|
|
25
|
+
client?.dispose();
|
|
26
|
+
client = undefined;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=sse.js.map
|
package/dist/sse.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.js","sourceRoot":"","sources":["../src/sse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAmC,MAAM,aAAa,CAAC;AAE5E,OAAO,EACL,QAAQ,EACR,MAAM,EAIP,MAAM,gBAAgB,CAAC;AAexB,MAAM,CAAC,MAAM,GAAG,GAA0B;IACxC,IAAI,EAAE,KAAK;IACX,OAAO,CAAC,QAAQ,EAAE,OAAO,GAAG,EAAE;QAC5B,IAAI,MAAmC,CAAC;QACxC,OAAO;YACL,KAAK,CAAC,CAAC,SAAS,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM;gBAC1C,MAAM,KAAK,YAAY,CAAC;oBACtB,GAAG,OAAO;oBACV,GAAG,EAAE,QAAQ,CAAC,GAAG;oBACjB,OAAO,EAAE,QAAQ,CAAC,KAAK;oBACvB,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAC;iBAClE,CAAC,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC;oBAC5B,KAAK,EAAE,QAAQ,CAAC,KAAK;oBACrB,SAAS,EAAE,SAAgD;oBAC3D,aAAa,EAAE,QAAQ,CAAC,IAAI;iBAC7B,CAAC,CAAC;gBACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;oBAAE,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAC;YAC1E,CAAC;YAED,SAAS,KAAI,CAAC;YACd,KAAK,EAAE,KAAK,IAAI,EAAE;gBAChB,MAAM,EAAE,OAAO,EAAE,CAAC;gBAClB,MAAM,GAAG,SAAS,CAAC;YACrB,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC"}
|
package/dist/test.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ServerOptions } from "graphql-ws";
|
|
2
|
+
import { type HeadersSource, type MaybePromise } from "./transport.js";
|
|
3
|
+
import type { Client, Operations, Transports } from "./types.js";
|
|
4
|
+
type Handler = (request: Request) => MaybePromise<Response>;
|
|
5
|
+
export type TestServer<O extends Operations = Operations> = {
|
|
6
|
+
http: Handler;
|
|
7
|
+
} & {
|
|
8
|
+
readonly [K in Transports<O>]: K extends "ws" ? ServerOptions<never, never> : Handler;
|
|
9
|
+
};
|
|
10
|
+
export declare function testClient<O extends Operations>(operations: O, server: TestServer<O> | ([Transports<O>] extends [never] ? Handler : never), options?: {
|
|
11
|
+
url?: string | URL;
|
|
12
|
+
headers?: HeadersSource;
|
|
13
|
+
}): Client<O>;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../src/test.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,aAAa,EACnB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,EAAiB,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEhF,KAAK,OAAO,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,YAAY,CAAC,QAAQ,CAAC,CAAC;AAM5D,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,IAAI;IAE1D,IAAI,EAAE,OAAO,CAAC;CACf,GAAG;IACF,QAAQ,EAAE,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,IAAI,GAKzC,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC,GAE3B,OAAO;CACZ,CAAC;AAoFF,wBAAgB,UAAU,CAAC,CAAC,SAAS,UAAU,EAC7C,UAAU,EAAE,CAAC,EACb,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,OAAO,GAAG,KAAK,CAAC,EAC3E,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;IAAC,OAAO,CAAC,EAAE,aAAa,CAAA;CAAO,GAC5D,MAAM,CAAC,CAAC,CAAC,CA0CX"}
|
package/dist/test.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { createClient as createSseClient } from "graphql-sse";
|
|
2
|
+
import { CloseCode, createClient as createWsClient, GRAPHQL_TRANSPORT_WS_PROTOCOL, makeServer } from "graphql-ws";
|
|
3
|
+
import { createClient } from "./index.js";
|
|
4
|
+
import { resolveHeaders } from "./transport.js";
|
|
5
|
+
function memoryWebSocket(options) {
|
|
6
|
+
const graphqlWs = makeServer(options);
|
|
7
|
+
return class Socket {
|
|
8
|
+
static CONNECTING = 0;
|
|
9
|
+
static OPEN = 1;
|
|
10
|
+
static CLOSING = 2;
|
|
11
|
+
static CLOSED = 3;
|
|
12
|
+
readyState = Socket.CONNECTING;
|
|
13
|
+
protocol = GRAPHQL_TRANSPORT_WS_PROTOCOL;
|
|
14
|
+
onopen = null;
|
|
15
|
+
onmessage = null;
|
|
16
|
+
onclose = null;
|
|
17
|
+
onerror = null;
|
|
18
|
+
#receive;
|
|
19
|
+
#closed;
|
|
20
|
+
constructor() {
|
|
21
|
+
queueMicrotask(() => {
|
|
22
|
+
this.#closed = graphqlWs.opened({
|
|
23
|
+
protocol: this.protocol,
|
|
24
|
+
send: (data) => {
|
|
25
|
+
if (this.readyState !== Socket.OPEN)
|
|
26
|
+
return;
|
|
27
|
+
queueMicrotask(() => this.onmessage?.({ data }));
|
|
28
|
+
},
|
|
29
|
+
close: (code, reason) => this.#finish(code, reason),
|
|
30
|
+
onMessage: (receive) => {
|
|
31
|
+
this.#receive = receive;
|
|
32
|
+
}
|
|
33
|
+
}, {});
|
|
34
|
+
this.readyState = Socket.OPEN;
|
|
35
|
+
this.onopen?.({});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
send(data) {
|
|
39
|
+
queueMicrotask(() => {
|
|
40
|
+
this.#receive?.(data).catch((error) => this.#finish(CloseCode.InternalServerError, error instanceof Error ? error.message : String(error)));
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
close(code = 1000, reason = "") {
|
|
44
|
+
this.#finish(code, reason);
|
|
45
|
+
}
|
|
46
|
+
#finish(code = 1000, reason = "") {
|
|
47
|
+
if (this.readyState === Socket.CLOSED)
|
|
48
|
+
return;
|
|
49
|
+
this.readyState = Socket.CLOSED;
|
|
50
|
+
void this.#closed?.(code, reason);
|
|
51
|
+
queueMicrotask(() => this.onclose?.({ code, reason, wasClean: true }));
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export function testClient(operations, server, options = {}) {
|
|
56
|
+
const handlers = (typeof server === "function" ? { http: server } : server);
|
|
57
|
+
for (const kind of operations.transports ?? []) {
|
|
58
|
+
if (!handlers[kind]) {
|
|
59
|
+
throw new Error(`These operations subscribe over ${kind}: pass testClient(operations, { http, ${kind} }) the app's own ${kind === "ws" ? "graphql-ws server options" : "graphql-sse handler"}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const url = String(options.url ?? "http://localhost/graphql");
|
|
63
|
+
const headers = async () => Object.fromEntries(await resolveHeaders(options.headers));
|
|
64
|
+
const fetch = async (target, init) => {
|
|
65
|
+
const request = new Request(target, init);
|
|
66
|
+
const streams = request.headers
|
|
67
|
+
.get("accept")
|
|
68
|
+
?.includes("text/event-stream");
|
|
69
|
+
return handlers.sse && streams
|
|
70
|
+
? handlers.sse(request)
|
|
71
|
+
: handlers.http(request);
|
|
72
|
+
};
|
|
73
|
+
return createClient(operations, {
|
|
74
|
+
url,
|
|
75
|
+
headers: options.headers,
|
|
76
|
+
fetch,
|
|
77
|
+
ws: handlers.ws &&
|
|
78
|
+
createWsClient({
|
|
79
|
+
url: url.replace(/^http/, "ws"),
|
|
80
|
+
webSocketImpl: memoryWebSocket(handlers.ws),
|
|
81
|
+
retryAttempts: 0,
|
|
82
|
+
connectionParams: async () => ({ headers: await headers() })
|
|
83
|
+
}),
|
|
84
|
+
sse: handlers.sse &&
|
|
85
|
+
createSseClient({ url, fetchFn: fetch, headers, retryAttempts: 0 })
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=test.js.map
|
package/dist/test.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.js","sourceRoot":"","sources":["../src/test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { GraphQLErrorJSON, HeadersValue, Result } from "./types.js";
|
|
2
|
+
export interface RequestParams {
|
|
3
|
+
query: string;
|
|
4
|
+
variables: unknown;
|
|
5
|
+
operationName: string;
|
|
6
|
+
}
|
|
7
|
+
export type Fetch = (url: string, init: RequestInit, params: RequestParams) => Promise<Response>;
|
|
8
|
+
export type MaybePromise<T> = T | Promise<T>;
|
|
9
|
+
export type HeadersSource = HeadersValue | (() => MaybePromise<HeadersValue>);
|
|
10
|
+
export declare const asResult: (body: {
|
|
11
|
+
data?: unknown;
|
|
12
|
+
errors?: readonly GraphQLErrorJSON[];
|
|
13
|
+
}) => Result<never>;
|
|
14
|
+
export declare function resolveHeaders(...sources: (HeadersSource | undefined)[]): Promise<Headers>;
|
|
15
|
+
export declare function stream<T>(events: AsyncIterableIterator<T>, signal: AbortSignal | undefined): AsyncGenerator<T>;
|
|
16
|
+
export declare function errorResult(error: unknown): Result<never> | undefined;
|
|
17
|
+
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB;AAKD,MAAM,MAAM,KAAK,GAAG,CAClB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,aAAa,KAClB,OAAO,CAAC,QAAQ,CAAC,CAAC;AACvB,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAE7C,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,CAAC,MAAM,YAAY,CAAC,YAAY,CAAC,CAAC,CAAC;AAE9E,eAAO,MAAM,QAAQ,SAAU;IAC7B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACtC,KAAG,MAAM,CAAC,KAAK,CAGd,CAAC;AAkBH,wBAAsB,cAAc,CAClC,GAAG,OAAO,EAAE,CAAC,aAAa,GAAG,SAAS,CAAC,EAAE,GACxC,OAAO,CAAC,OAAO,CAAC,CASlB;AAGD,wBAAuB,MAAM,CAAC,CAAC,EAC7B,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC,EAChC,MAAM,EAAE,WAAW,GAAG,SAAS,GAC9B,cAAc,CAAC,CAAC,CAAC,CAQnB;AAkBD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,SAAS,CAcrE"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export const asResult = (body) => ({
|
|
2
|
+
data: (body.data ?? null),
|
|
3
|
+
...(body.errors ? { errors: body.errors } : {})
|
|
4
|
+
});
|
|
5
|
+
function entries(headers) {
|
|
6
|
+
if (headers === undefined ||
|
|
7
|
+
Array.isArray(headers) ||
|
|
8
|
+
headers instanceof Headers) {
|
|
9
|
+
return new Headers(headers);
|
|
10
|
+
}
|
|
11
|
+
return Object.entries(headers).filter((entry) => entry[1] !== undefined);
|
|
12
|
+
}
|
|
13
|
+
export async function resolveHeaders(...sources) {
|
|
14
|
+
const resolved = await Promise.all(sources.map((source) => (typeof source === "function" ? source() : source)));
|
|
15
|
+
const merged = new Headers();
|
|
16
|
+
for (const headers of resolved) {
|
|
17
|
+
for (const [key, value] of entries(headers))
|
|
18
|
+
merged.set(key, value);
|
|
19
|
+
}
|
|
20
|
+
return merged;
|
|
21
|
+
}
|
|
22
|
+
export async function* stream(events, signal) {
|
|
23
|
+
const stop = () => void events.return?.();
|
|
24
|
+
signal?.addEventListener("abort", stop, { once: true });
|
|
25
|
+
try {
|
|
26
|
+
yield* events;
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
signal?.removeEventListener("abort", stop);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const isClose = (error) => typeof error === "object" &&
|
|
33
|
+
error !== null &&
|
|
34
|
+
"code" in error &&
|
|
35
|
+
"reason" in error;
|
|
36
|
+
export function errorResult(error) {
|
|
37
|
+
if (Array.isArray(error)) {
|
|
38
|
+
return asResult({ errors: error });
|
|
39
|
+
}
|
|
40
|
+
if (!isClose(error) || error.code < 4000 || error.code > 4999)
|
|
41
|
+
return;
|
|
42
|
+
return {
|
|
43
|
+
data: null,
|
|
44
|
+
errors: [
|
|
45
|
+
{
|
|
46
|
+
message: error.reason || `WebSocket closed (${error.code})`,
|
|
47
|
+
extensions: { code: "WEBSOCKET_CLOSED", closeCode: error.code }
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAoBA,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAGxB,EAAiB,EAAE,CAAC,CAAC;IACpB,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAU;IAClC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;CAChD,CAAC,CAAC;AAGH,SAAS,OAAO,CACd,OAAiC;IAEjC,IACE,OAAO,KAAK,SAAS;QACrB,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QACtB,OAAO,YAAY,OAAO,EAC1B,CAAC;QACD,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,CACnC,CAAC,KAAK,EAA6B,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,CAC7D,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAG,OAAsC;IAEzC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAChC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAC5E,CAAC;IACF,MAAM,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;IAC7B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC;YAAE,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAGD,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,MAAM,CAC3B,MAAgC,EAChC,MAA+B;IAE/B,MAAM,IAAI,GAAG,GAAS,EAAE,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;IAChD,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,IAAI,CAAC;QACH,KAAK,CAAC,CAAC,MAAM,CAAC;IAChB,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAOD,MAAM,OAAO,GAAG,CAAC,KAAc,EAAuB,EAAE,CACtD,OAAO,KAAK,KAAK,QAAQ;IACzB,KAAK,KAAK,IAAI;IACd,MAAM,IAAI,KAAK;IACf,QAAQ,IAAI,KAAK,CAAC;AAOpB,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,QAAQ,CAAC,EAAE,MAAM,EAAE,KAA2B,EAAE,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,GAAG,IAAI,IAAI,KAAK,CAAC,IAAI,GAAG,IAAI;QAAE,OAAO;IACtE,OAAO;QACL,IAAI,EAAE,IAAI;QACV,MAAM,EAAE;YACN;gBACE,OAAO,EAAE,KAAK,CAAC,MAAM,IAAI,qBAAqB,KAAK,CAAC,IAAI,GAAG;gBAC3D,UAAU,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE;aAChE;SACF;KACF,CAAC;AACJ,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { Fetch, HeadersSource } from "./transport.js";
|
|
2
|
+
export interface ClientScalars {
|
|
3
|
+
}
|
|
4
|
+
interface DefaultScalars {
|
|
5
|
+
ID: string;
|
|
6
|
+
String: string;
|
|
7
|
+
Int: number;
|
|
8
|
+
Float: number;
|
|
9
|
+
Boolean: boolean;
|
|
10
|
+
}
|
|
11
|
+
export type Scalar<N extends string, D extends "input" | "output" = "output"> = N extends keyof ClientScalars ? ClientScalars[N] extends {
|
|
12
|
+
input: infer I;
|
|
13
|
+
output: infer O;
|
|
14
|
+
} ? D extends "input" ? I : O : ClientScalars[N] : N extends keyof DefaultScalars ? DefaultScalars[N] : unknown;
|
|
15
|
+
export type Operation = "query" | "mutation" | "subscription";
|
|
16
|
+
export interface TypedDocument<Result, Variables, Op extends Operation = Operation> {
|
|
17
|
+
readonly operation: Op;
|
|
18
|
+
readonly name: string;
|
|
19
|
+
readonly query: string;
|
|
20
|
+
readonly transport?: "ws" | "sse";
|
|
21
|
+
readonly "~types"?: {
|
|
22
|
+
result: Result;
|
|
23
|
+
variables: Variables;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export interface GraphQLErrorJSON {
|
|
27
|
+
message: string;
|
|
28
|
+
locations?: readonly {
|
|
29
|
+
line: number;
|
|
30
|
+
column: number;
|
|
31
|
+
}[];
|
|
32
|
+
path?: readonly (string | number)[];
|
|
33
|
+
extensions?: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
export interface Result<T> {
|
|
36
|
+
data: T | null;
|
|
37
|
+
errors?: readonly GraphQLErrorJSON[];
|
|
38
|
+
}
|
|
39
|
+
export type HeadersInit = ConstructorParameters<typeof Headers>[0];
|
|
40
|
+
export type HeadersValue = HeadersInit | Readonly<Record<string, string | undefined>>;
|
|
41
|
+
export interface CallOptions {
|
|
42
|
+
signal?: AbortSignal;
|
|
43
|
+
headers?: HeadersValue;
|
|
44
|
+
}
|
|
45
|
+
type RequiredKeys<T> = {
|
|
46
|
+
[K in keyof T]-?: object extends Pick<T, K> ? never : K;
|
|
47
|
+
}[keyof T];
|
|
48
|
+
export type VariablesArgs<V, O> = [RequiredKeys<V>] extends [never] ? [variables?: V, options?: O] : [variables: V, options?: O];
|
|
49
|
+
interface AnyDocument<Op extends Operation> {
|
|
50
|
+
readonly operation: Op;
|
|
51
|
+
readonly name: string;
|
|
52
|
+
readonly query: string;
|
|
53
|
+
readonly transport?: "ws" | "sse";
|
|
54
|
+
}
|
|
55
|
+
export interface Operations {
|
|
56
|
+
readonly query?: Readonly<Record<string, AnyDocument<"query">>>;
|
|
57
|
+
readonly mutation?: Readonly<Record<string, AnyDocument<"mutation">>>;
|
|
58
|
+
readonly subscription?: Readonly<Record<string, AnyDocument<"subscription">>>;
|
|
59
|
+
readonly transports?: readonly ("ws" | "sse")[];
|
|
60
|
+
}
|
|
61
|
+
export interface SubscriptionClient {
|
|
62
|
+
iterate(request: {
|
|
63
|
+
query: string;
|
|
64
|
+
variables?: Record<string, unknown>;
|
|
65
|
+
operationName?: string;
|
|
66
|
+
}): AsyncIterableIterator<{
|
|
67
|
+
data?: unknown;
|
|
68
|
+
errors?: readonly GraphQLErrorJSON[];
|
|
69
|
+
}>;
|
|
70
|
+
}
|
|
71
|
+
type Call<D> = D extends TypedDocument<infer R, infer V, infer Op> ? Op extends "subscription" ? (...args: VariablesArgs<V, Pick<CallOptions, "signal">>) => AsyncIterableIterator<Result<R>> : (...args: VariablesArgs<V, CallOptions>) => Promise<Result<R>> : never;
|
|
72
|
+
export type Client<O extends Operations> = {
|
|
73
|
+
readonly [Op in keyof O & Operation]: {
|
|
74
|
+
readonly [K in keyof O[Op]]: Call<O[Op][K]>;
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
export type Transports<O extends Operations> = O extends {
|
|
78
|
+
transports: readonly (infer K)[];
|
|
79
|
+
} ? K & ("ws" | "sse") : never;
|
|
80
|
+
export type ClientOptions<O extends Operations> = {
|
|
81
|
+
url: string | URL;
|
|
82
|
+
headers?: HeadersSource;
|
|
83
|
+
fetch?: Fetch;
|
|
84
|
+
} & {
|
|
85
|
+
readonly [K in Transports<O>]: SubscriptionClient;
|
|
86
|
+
};
|
|
87
|
+
export {};
|
|
88
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/dist/ws.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ClientOptions } from "graphql-ws/client";
|
|
2
|
+
import { type MaybePromise, type Transport } from "./transport.js";
|
|
3
|
+
export interface WsOptions extends Omit<ClientOptions, "url" | "connectionParams" | "webSocketImpl"> {
|
|
4
|
+
url?: string | URL;
|
|
5
|
+
connectionParams?: Record<string, unknown> | (() => MaybePromise<Record<string, unknown>>);
|
|
6
|
+
webSocket?: unknown;
|
|
7
|
+
}
|
|
8
|
+
export declare const ws: Transport<WsOptions>;
|
|
9
|
+
//# sourceMappingURL=ws.d.ts.map
|
package/dist/ws.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../src/ws.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAErE,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAIxB,MAAM,WAAW,SAAU,SAAQ,IAAI,CACrC,aAAa,EACb,KAAK,GAAG,kBAAkB,GAAG,eAAe,CAC7C;IAEC,GAAG,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;IAKnB,gBAAgB,CAAC,EACb,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvB,CAAC,MAAM,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAElD,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AA0BD,eAAO,MAAM,EAAE,EAAE,SAAS,CAAC,SAAS,CA4CnC,CAAC"}
|
package/dist/ws.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { createClient } from "graphql-ws/client";
|
|
2
|
+
import { asResult, stream } from "./transport.js";
|
|
3
|
+
const isClose = (error) => typeof error === "object" &&
|
|
4
|
+
error !== null &&
|
|
5
|
+
"code" in error &&
|
|
6
|
+
"reason" in error;
|
|
7
|
+
const refused = ({ code, reason }) => ({
|
|
8
|
+
data: null,
|
|
9
|
+
errors: [
|
|
10
|
+
{
|
|
11
|
+
message: reason || `WebSocket closed (${code})`,
|
|
12
|
+
extensions: { code: "WEBSOCKET_CLOSED", closeCode: code }
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
});
|
|
16
|
+
export const ws = {
|
|
17
|
+
kind: "ws",
|
|
18
|
+
connect(endpoint, options = {}) {
|
|
19
|
+
const client = createClient({
|
|
20
|
+
lazy: true,
|
|
21
|
+
...options,
|
|
22
|
+
url: endpoint.url,
|
|
23
|
+
webSocketImpl: options.webSocket,
|
|
24
|
+
connectionParams: async () => {
|
|
25
|
+
const params = options.connectionParams;
|
|
26
|
+
if (params)
|
|
27
|
+
return typeof params === "function" ? params() : params;
|
|
28
|
+
return { headers: Object.fromEntries(await endpoint.headers()) };
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
return {
|
|
32
|
+
async *subscribe(document, variables, signal) {
|
|
33
|
+
const events = client.iterate({
|
|
34
|
+
query: document.query,
|
|
35
|
+
variables: variables,
|
|
36
|
+
operationName: document.name
|
|
37
|
+
});
|
|
38
|
+
try {
|
|
39
|
+
for await (const event of stream(events, signal))
|
|
40
|
+
yield asResult(event);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (Array.isArray(error)) {
|
|
44
|
+
yield asResult({ errors: error });
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (!isClose(error) || error.code < 4000 || error.code > 4999) {
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
yield refused(error);
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
reconnect: () => client.terminate(),
|
|
54
|
+
close: async () => {
|
|
55
|
+
await client.dispose();
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=ws.js.map
|
package/dist/ws.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws.js","sourceRoot":"","sources":["../src/ws.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAsB,MAAM,mBAAmB,CAAC;AAErE,OAAO,EACL,QAAQ,EACR,MAAM,EAGP,MAAM,gBAAgB,CAAC;AA0BxB,MAAM,OAAO,GAAG,CAAC,KAAc,EAAuB,EAAE,CACtD,OAAO,KAAK,KAAK,QAAQ;IACzB,KAAK,KAAK,IAAI;IACd,MAAM,IAAI,KAAK;IACf,QAAQ,IAAI,KAAK,CAAC;AAIpB,MAAM,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,MAAM,EAAc,EAAiB,EAAE,CAAC,CAAC;IAChE,IAAI,EAAE,IAAI;IACV,MAAM,EAAE;QACN;YACE,OAAO,EAAE,MAAM,IAAI,qBAAqB,IAAI,GAAG;YAC/C,UAAU,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,SAAS,EAAE,IAAI,EAAE;SAC1D;KACF;CACF,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,EAAE,GAAyB;IACtC,IAAI,EAAE,IAAI;IACV,OAAO,CAAC,QAAQ,EAAE,OAAO,GAAG,EAAE;QAC5B,MAAM,MAAM,GAAG,YAAY,CAAC;YAC1B,IAAI,EAAE,IAAI;YACV,GAAG,OAAO;YACV,GAAG,EAAE,QAAQ,CAAC,GAAG;YACjB,aAAa,EAAE,OAAO,CAAC,SAAS;YAChC,gBAAgB,EAAE,KAAK,IAAI,EAAE;gBAC3B,MAAM,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;gBACxC,IAAI,MAAM;oBAAE,OAAO,OAAO,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;gBACpE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;YACnE,CAAC;SACF,CAAC,CAAC;QACH,OAAO;YACL,KAAK,CAAC,CAAC,SAAS,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM;gBAC1C,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC;oBAC5B,KAAK,EAAE,QAAQ,CAAC,KAAK;oBACrB,SAAS,EAAE,SAAgD;oBAC3D,aAAa,EAAE,QAAQ,CAAC,IAAI;iBAC7B,CAAC,CAAC;gBACH,IAAI,CAAC;oBACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;wBAC9C,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAC;gBAC1B,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBAGf,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;wBACzB,MAAM,QAAQ,CAAC,EAAE,MAAM,EAAE,KAA2B,EAAE,CAAC,CAAC;wBACxD,OAAO;oBACT,CAAC;oBACD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,GAAG,IAAI,IAAI,KAAK,CAAC,IAAI,GAAG,IAAI,EAAE,CAAC;wBAC9D,MAAM,KAAK,CAAC;oBACd,CAAC;oBACD,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;gBACvB,CAAC;YACH,CAAC;YAED,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE;YACnC,KAAK,EAAE,KAAK,IAAI,EAAE;gBAChB,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;YACzB,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,54 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nxara/olio-client",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0-rc.1",
|
|
4
|
+
"description": "A typed GraphQL client for Nxara apps: select fields, get typed results.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"client",
|
|
7
|
+
"graphql",
|
|
8
|
+
"nxara",
|
|
9
|
+
"rpc"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/nxara-hub/olio.git",
|
|
15
|
+
"directory": "packages/client"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"type": "module",
|
|
21
|
+
"sideEffects": false,
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"default": "./dist/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./test": {
|
|
28
|
+
"types": "./dist/test.d.ts",
|
|
29
|
+
"default": "./dist/test.js"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc",
|
|
37
|
+
"test": "bun test",
|
|
38
|
+
"check-types": "bun test/generate.ts && tsc -p tsconfig.test.json"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"graphql-sse": "2.6.3",
|
|
42
|
+
"graphql-ws": "^6.4.1"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@nxara/olio": "0.1.0-rc.1",
|
|
46
|
+
"@nxara/olio-codegen": "0.1.0-rc.1",
|
|
47
|
+
"@nxara/olio-http": "0.1.0-rc.1",
|
|
48
|
+
"graphql": "^16.14.2",
|
|
49
|
+
"ky": "^2.2.0"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"graphql": "^16.13.0"
|
|
53
|
+
}
|
|
54
|
+
}
|