@graphorin/client 0.6.1 → 0.7.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.
- package/CHANGELOG.md +21 -0
- package/README.md +2 -2
- package/dist/errors.d.ts +7 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/graphorin-client.d.ts +22 -0
- package/dist/graphorin-client.d.ts.map +1 -1
- package/dist/graphorin-client.js +17 -2
- package/dist/graphorin-client.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/dist/reconnect.d.ts +3 -3
- package/dist/reconnect.js +2 -2
- package/dist/reconnect.js.map +1 -1
- package/dist/transport/types.d.ts +1 -1
- package/package.json +12 -11
- package/src/errors.ts +170 -0
- package/src/graphorin-client.ts +1075 -0
- package/src/index.ts +49 -0
- package/src/reconnect.ts +91 -0
- package/src/transport/index.ts +16 -0
- package/src/transport/sse.ts +174 -0
- package/src/transport/types.ts +106 -0
- package/src/transport/ws.ts +211 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graphorin/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Reference TypeScript client for the Graphorin standalone server. Wraps the WebSocket subprotocol `graphorin.protocol.v1` (with the optional Server-Sent Events fallback for proxy-restricted environments) behind an ergonomic `GraphorinClient` class: `connect()`, `subscribe({ target, id })` returning an async-iterable subscription, `cancel(runId, opts)`, `resume(runId, directive)`, `ping()`, `disconnect()`. Handles the browser ticket flow (single-use ticket attached as a `ticket.<value>` `Sec-WebSocket-Protocol` token), exponential-backoff reconnect with `lastEventId` resume against the server replay buffer, and Zod-validated frame parsing on both directions. Browser-friendly: zero Node-only dependencies; the only runtime dependencies are `@graphorin/protocol` and `zod`. Created and maintained by Oleksiy Stepurenko.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Oleksiy Stepurenko",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
],
|
|
28
28
|
"type": "module",
|
|
29
29
|
"engines": {
|
|
30
|
-
"node": ">=22.
|
|
30
|
+
"node": ">=22.12.0"
|
|
31
31
|
},
|
|
32
32
|
"main": "./dist/index.js",
|
|
33
33
|
"module": "./dist/index.js",
|
|
@@ -36,35 +36,36 @@
|
|
|
36
36
|
"exports": {
|
|
37
37
|
".": {
|
|
38
38
|
"types": "./dist/index.d.ts",
|
|
39
|
-
"
|
|
39
|
+
"default": "./dist/index.js"
|
|
40
40
|
},
|
|
41
41
|
"./client": {
|
|
42
42
|
"types": "./dist/graphorin-client.d.ts",
|
|
43
|
-
"
|
|
43
|
+
"default": "./dist/graphorin-client.js"
|
|
44
44
|
},
|
|
45
45
|
"./transport": {
|
|
46
46
|
"types": "./dist/transport/index.d.ts",
|
|
47
|
-
"
|
|
47
|
+
"default": "./dist/transport/index.js"
|
|
48
48
|
},
|
|
49
49
|
"./reconnect": {
|
|
50
50
|
"types": "./dist/reconnect.d.ts",
|
|
51
|
-
"
|
|
51
|
+
"default": "./dist/reconnect.js"
|
|
52
52
|
},
|
|
53
53
|
"./errors": {
|
|
54
54
|
"types": "./dist/errors.d.ts",
|
|
55
|
-
"
|
|
55
|
+
"default": "./dist/errors.js"
|
|
56
56
|
},
|
|
57
57
|
"./package.json": "./package.json"
|
|
58
58
|
},
|
|
59
59
|
"files": [
|
|
60
60
|
"dist",
|
|
61
|
+
"src",
|
|
61
62
|
"README.md",
|
|
62
63
|
"CHANGELOG.md",
|
|
63
64
|
"LICENSE"
|
|
64
65
|
],
|
|
65
66
|
"dependencies": {
|
|
66
67
|
"zod": "^3.25.0",
|
|
67
|
-
"@graphorin/protocol": "0.
|
|
68
|
+
"@graphorin/protocol": "0.7.0"
|
|
68
69
|
},
|
|
69
70
|
"publishConfig": {
|
|
70
71
|
"access": "public",
|
|
@@ -73,9 +74,9 @@
|
|
|
73
74
|
"devDependencies": {
|
|
74
75
|
"@types/ws": "^8.18.1",
|
|
75
76
|
"ws": "^8.20.1",
|
|
76
|
-
"@graphorin/security": "0.
|
|
77
|
-
"@graphorin/server": "0.
|
|
78
|
-
"@graphorin/store-sqlite": "0.
|
|
77
|
+
"@graphorin/security": "0.7.0",
|
|
78
|
+
"@graphorin/server": "0.7.0",
|
|
79
|
+
"@graphorin/store-sqlite": "0.7.0"
|
|
79
80
|
},
|
|
80
81
|
"scripts": {
|
|
81
82
|
"build": "tsdown",
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed error hierarchy surfaced by `@graphorin/client`. Every error
|
|
3
|
+
* class extends the JavaScript built-in `Error` and exposes a stable
|
|
4
|
+
* `kind` discriminator so consumers can pattern-match without
|
|
5
|
+
* relying on `instanceof` (which behaves badly across module-system
|
|
6
|
+
* boundaries when the package is dual-loaded).
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { RPC_ERROR_CODES } from '@graphorin/protocol';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* IP-19: map a JSON-RPC error code from a server `RpcFailure` frame to the
|
|
15
|
+
* client's discriminated {@link GraphorinClientErrorKind}, so a rate-limited
|
|
16
|
+
* or scope-denied RPC is distinguishable from a genuine protocol violation.
|
|
17
|
+
*/
|
|
18
|
+
export function kindForRpcCode(code: number): GraphorinClientErrorKind {
|
|
19
|
+
switch (code) {
|
|
20
|
+
case RPC_ERROR_CODES.RATE_LIMITED:
|
|
21
|
+
return 'rate-limited';
|
|
22
|
+
case RPC_ERROR_CODES.SCOPE_DENIED:
|
|
23
|
+
return 'scope-denied';
|
|
24
|
+
case RPC_ERROR_CODES.AUTH_REQUIRED:
|
|
25
|
+
case RPC_ERROR_CODES.AUTH_INVALID:
|
|
26
|
+
return 'auth-failed';
|
|
27
|
+
case RPC_ERROR_CODES.RUN_NOT_FOUND:
|
|
28
|
+
return 'run-not-found';
|
|
29
|
+
case RPC_ERROR_CODES.SUBSCRIPTION_NOT_FOUND:
|
|
30
|
+
return 'subscription-not-found';
|
|
31
|
+
case RPC_ERROR_CODES.INTERNAL_ERROR:
|
|
32
|
+
return 'server-error';
|
|
33
|
+
default:
|
|
34
|
+
// INVALID_REQUEST / INVALID_PARAMS / METHOD_NOT_FOUND / PROTOCOL_VIOLATION
|
|
35
|
+
// and any unknown code stay a protocol violation.
|
|
36
|
+
return 'protocol-violation';
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Discriminator union of every error kind raised by the client.
|
|
42
|
+
*
|
|
43
|
+
* @stable
|
|
44
|
+
*/
|
|
45
|
+
export type GraphorinClientErrorKind =
|
|
46
|
+
| 'client-not-connected'
|
|
47
|
+
| 'transport-failed'
|
|
48
|
+
| 'subprotocol-mismatch'
|
|
49
|
+
| 'auth-failed'
|
|
50
|
+
| 'protocol-violation'
|
|
51
|
+
| 'subscription-not-found'
|
|
52
|
+
// IP-19: discriminated RPC-failure kinds so callers can branch on the
|
|
53
|
+
// server's error class instead of pattern-matching the message string.
|
|
54
|
+
| 'rate-limited'
|
|
55
|
+
| 'scope-denied'
|
|
56
|
+
| 'run-not-found'
|
|
57
|
+
| 'server-error'
|
|
58
|
+
| 'aborted'
|
|
59
|
+
/**
|
|
60
|
+
* W-152: the per-subscription client buffer hit
|
|
61
|
+
* `subscriptionQueueLimit` because the `for await` consumer fell
|
|
62
|
+
* behind the event flow; the subscription is closed with this typed
|
|
63
|
+
* error instead of growing the heap or silently dropping frames.
|
|
64
|
+
*/
|
|
65
|
+
| 'flow-overflow'
|
|
66
|
+
| 'invalid-server-frame';
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Base class for every error raised by `@graphorin/client`. Carries a
|
|
70
|
+
* stable {@link GraphorinClientErrorKind} discriminator and an
|
|
71
|
+
* optional `cause` chain.
|
|
72
|
+
*
|
|
73
|
+
* @stable
|
|
74
|
+
*/
|
|
75
|
+
export class GraphorinClientError extends Error {
|
|
76
|
+
readonly kind: GraphorinClientErrorKind;
|
|
77
|
+
|
|
78
|
+
constructor(kind: GraphorinClientErrorKind, message: string, options: ErrorOptions = {}) {
|
|
79
|
+
super(message, options);
|
|
80
|
+
this.kind = kind;
|
|
81
|
+
this.name = 'GraphorinClientError';
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** @stable */
|
|
86
|
+
export class ClientNotConnectedError extends GraphorinClientError {
|
|
87
|
+
constructor(message = 'GraphorinClient is not connected. Call connect() first.') {
|
|
88
|
+
super('client-not-connected', message);
|
|
89
|
+
this.name = 'ClientNotConnectedError';
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** @stable */
|
|
94
|
+
export class TransportFailedError extends GraphorinClientError {
|
|
95
|
+
readonly code: number | undefined;
|
|
96
|
+
|
|
97
|
+
constructor(message: string, options: ErrorOptions & { readonly code?: number } = {}) {
|
|
98
|
+
super('transport-failed', message, options);
|
|
99
|
+
this.name = 'TransportFailedError';
|
|
100
|
+
this.code = options.code;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** @stable */
|
|
105
|
+
export class SubprotocolMismatchError extends GraphorinClientError {
|
|
106
|
+
readonly expected: string;
|
|
107
|
+
readonly actual: string | null;
|
|
108
|
+
|
|
109
|
+
constructor(expected: string, actual: string | null) {
|
|
110
|
+
super(
|
|
111
|
+
'subprotocol-mismatch',
|
|
112
|
+
`Server selected subprotocol '${actual ?? '<none>'}'; expected '${expected}'.`,
|
|
113
|
+
);
|
|
114
|
+
this.name = 'SubprotocolMismatchError';
|
|
115
|
+
this.expected = expected;
|
|
116
|
+
this.actual = actual;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** @stable */
|
|
121
|
+
export class AuthFailedError extends GraphorinClientError {
|
|
122
|
+
constructor(message = 'Authentication failed. Re-mint a token or request a new ticket.') {
|
|
123
|
+
super('auth-failed', message);
|
|
124
|
+
this.name = 'AuthFailedError';
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** @stable */
|
|
129
|
+
export class ProtocolViolationError extends GraphorinClientError {
|
|
130
|
+
constructor(message: string, options: ErrorOptions = {}) {
|
|
131
|
+
super('protocol-violation', message, options);
|
|
132
|
+
this.name = 'ProtocolViolationError';
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** @stable */
|
|
137
|
+
export class SubscriptionNotFoundError extends GraphorinClientError {
|
|
138
|
+
readonly subscriptionId: string;
|
|
139
|
+
|
|
140
|
+
constructor(subscriptionId: string) {
|
|
141
|
+
super(
|
|
142
|
+
'subscription-not-found',
|
|
143
|
+
`Subscription '${subscriptionId}' is not active on this client.`,
|
|
144
|
+
);
|
|
145
|
+
this.name = 'SubscriptionNotFoundError';
|
|
146
|
+
this.subscriptionId = subscriptionId;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** @stable */
|
|
151
|
+
export class ClientAbortedError extends GraphorinClientError {
|
|
152
|
+
constructor(message = 'Operation aborted before completion.') {
|
|
153
|
+
super('aborted', message);
|
|
154
|
+
this.name = 'ClientAbortedError';
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** @stable */
|
|
159
|
+
export class InvalidServerFrameError extends GraphorinClientError {
|
|
160
|
+
readonly issues: ReadonlyArray<{ path: ReadonlyArray<string | number>; message: string }>;
|
|
161
|
+
|
|
162
|
+
constructor(
|
|
163
|
+
message: string,
|
|
164
|
+
issues: ReadonlyArray<{ path: ReadonlyArray<string | number>; message: string }>,
|
|
165
|
+
) {
|
|
166
|
+
super('invalid-server-frame', message);
|
|
167
|
+
this.name = 'InvalidServerFrameError';
|
|
168
|
+
this.issues = issues;
|
|
169
|
+
}
|
|
170
|
+
}
|