@theritual/hayson-ts-client 2.0.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/LICENSE +21 -0
- package/README.md +65 -0
- package/package.json +59 -0
- package/proto/hayson.proto +266 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ritual
|
|
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
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# @theritual/hayson-ts-client
|
|
2
|
+
|
|
3
|
+
Klient TypeScript do `hayson-server`. Wyłącznie tryb zdalny (gRPC przez `@grpc/grpc-js`) — bazę
|
|
4
|
+
osadzoną w procesie obsługuje `@theritual/hayson`.
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
import { HaysonClient } from '@theritual/hayson-ts-client'
|
|
8
|
+
|
|
9
|
+
const client = await HaysonClient.open('127.0.0.1:50051', '/var/lib/moja-baza')
|
|
10
|
+
|
|
11
|
+
await client.createTable('users', usersSchema)
|
|
12
|
+
await client.put('users', { id: 'u1', name: 'Ada', role: 'admin' })
|
|
13
|
+
|
|
14
|
+
const admins = await client.query('users', { where: { field: 'role', op: 'eq', value: 'admin' } })
|
|
15
|
+
for await (const user of client.queryStream('users', { chunkSize: 500 })) report(user)
|
|
16
|
+
|
|
17
|
+
const unit = await client.beginTransaction()
|
|
18
|
+
await unit.put('users', { id: 'u2', name: 'Bo' })
|
|
19
|
+
await unit.commit()
|
|
20
|
+
|
|
21
|
+
await client.close()
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`HaysonClient.open(address, databaseDir, options?)` łączy się, wysyła `API_VERSION` (ADR-96fd —
|
|
25
|
+
jako metadane `x-hayson-api-version` przy każdym wywołaniu, nie jako pole `Open`) i trzyma
|
|
26
|
+
`clientId` sesji. Serwer mówiący inną wersją odmawia wywołania i podaje swoją wersję w tym samym
|
|
27
|
+
nagłówku — klient zgłasza to jako `HaysonApiVersionError`, czytając nagłówek, nie treść komunikatu. `address` przyjmuje obie formy — `host:port` (to, co wypisuje serwer przy
|
|
28
|
+
starcie) i `http://host:port` — tak samo jak `hayson-rust-client`; `https://` jest odrzucane od razu,
|
|
29
|
+
bo transport nie ma dziś TLS-a. `databaseDir` rozwiązuje **serwer**, nie proces klienta.
|
|
30
|
+
|
|
31
|
+
**Uwierzytelnienie.** `hayson-server` domyślnie generuje token przy starcie (albo bierze stały
|
|
32
|
+
z `HAYSON_SERVER_TOKEN`) i wymaga go jako `authorization: Bearer <token>` na każdym RPC. Podaj go
|
|
33
|
+
klientowi przez `options.token` — trafia automatycznie do każdego wywołania w tej sesji, nie tylko
|
|
34
|
+
do `open`:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
const client = await HaysonClient.open('127.0.0.1:50051', '/var/lib/moja-baza', { token })
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Brak albo zły token kończy się `HaysonRpcError` z kodem gRPC `UNAUTHENTICATED`, nie cichym zawieszeniem.
|
|
41
|
+
|
|
42
|
+
Metody odwzorowują `Database`/`Table` silnika: `put`, `patch`, `delete`, `get`, `query`,
|
|
43
|
+
`queryStream`, `aggregate`, `aggregateGrouped`, `beginTransaction`, `createTable`, `dropField`,
|
|
44
|
+
`declareIndex`, `declareTrigger`, `tables`, `describeTable`, `relations`, `checkIntegrity`,
|
|
45
|
+
`compact`, `compactAll`, `checkpoint`, `close`. Każda przyjmuje na końcu `RequestOptions` (`signal`, `deadlineMs`), a metody
|
|
46
|
+
piszące dodatkowo `force`.
|
|
47
|
+
|
|
48
|
+
Dokumenty i specyfikacje (schema, index, trigger) przechodzą jako zwykłe obiekty JSON w tych samych
|
|
49
|
+
kształtach, które przyjmuje silnik; predykat i agregat są otypowane (`Predicate`, `AggregateQuery`).
|
|
50
|
+
Wszystko, czego nie da się przenieść jako JSON (instancja klasy, `NaN`, `Infinity`), jest odrzucane
|
|
51
|
+
na granicy klienta, zanim ruszy przez drut.
|
|
52
|
+
|
|
53
|
+
Błędy: `HaysonClientError` i jego podklasy — `HaysonConnectionError`, `HaysonApiVersionError`,
|
|
54
|
+
`HaysonRpcError` (kod gRPC plus komunikat serwera), `HaysonPayloadError`, `HaysonDecodeError`,
|
|
55
|
+
`HaysonClosedError`. Uwaga: `hayson-server` mapuje dziś większość odmów na `INTERNAL`, więc
|
|
56
|
+
rozgałęziaj się po kodzie, nigdy po treści komunikatu.
|
|
57
|
+
|
|
58
|
+
Kontrakt sieciowy: `proto/hayson.proto` to kopia `crates/hayson-protocol/proto/hayson.proto`,
|
|
59
|
+
ładowana w runtime i pilnowana testem (`test/package.test.ts`) — obie muszą być bajt w bajt
|
|
60
|
+
identyczne.
|
|
61
|
+
|
|
62
|
+
Testy jadą przeciw prawdziwej binarce serwera: `cargo build -p hayson-server` z katalogu `crates/`,
|
|
63
|
+
potem `pnpm --filter @theritual/hayson-ts-client test:run`.
|
|
64
|
+
|
|
65
|
+
Plan pracy i otwarte pytania: cerebro `PLAN-6j76`. Decyzja o konwencji wersjonowania: `ADR-26tj`.
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@theritual/hayson-ts-client",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "TypeScript client for hayson-server — a remote hayson database over gRPC",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"database",
|
|
7
|
+
"grpc",
|
|
8
|
+
"client",
|
|
9
|
+
"hayson"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://gl.theritual.eu/ritual/hayson.git",
|
|
15
|
+
"directory": "packages/hayson-ts-client"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://gl.theritual.eu/ritual/hayson",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://gl.theritual.eu/ritual/hayson/-/issues"
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public",
|
|
23
|
+
"registry": "https://registry.npmjs.org/"
|
|
24
|
+
},
|
|
25
|
+
"type": "module",
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=24"
|
|
28
|
+
},
|
|
29
|
+
"main": "./dist/index.js",
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"default": "./dist/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./package.json": "./package.json"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist",
|
|
40
|
+
"proto",
|
|
41
|
+
"README.md",
|
|
42
|
+
"LICENSE"
|
|
43
|
+
],
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^24",
|
|
46
|
+
"typescript": "7.0.2",
|
|
47
|
+
"vitest": "^4.1.10"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@grpc/grpc-js": "^1.14.4",
|
|
51
|
+
"@grpc/proto-loader": "^0.8.1"
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build": "tsc -p tsconfig.build.json",
|
|
55
|
+
"check-types": "tsc --noEmit",
|
|
56
|
+
"test": "vitest",
|
|
57
|
+
"test:run": "vitest run"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
|
|
3
|
+
package hayson;
|
|
4
|
+
|
|
5
|
+
import "google/protobuf/struct.proto";
|
|
6
|
+
|
|
7
|
+
// Full RPC surface of hayson-server, per ADR-6b6m. All 25 RPCs below are implemented —
|
|
8
|
+
// none return UNIMPLEMENTED.
|
|
9
|
+
service Hayson {
|
|
10
|
+
rpc Open(OpenRequest) returns (OpenResponse);
|
|
11
|
+
rpc Close(CloseRequest) returns (CloseResponse);
|
|
12
|
+
|
|
13
|
+
rpc Put(PutRequest) returns (WriteResponse);
|
|
14
|
+
rpc Patch(PatchRequest) returns (WriteResponse);
|
|
15
|
+
rpc Delete(DeleteRequest) returns (WriteResponse);
|
|
16
|
+
|
|
17
|
+
rpc Get(GetRequest) returns (GetResponse);
|
|
18
|
+
rpc Query(QueryRequest) returns (stream QueryResultChunk);
|
|
19
|
+
rpc Aggregate(AggregateRequest) returns (AggregateResponse);
|
|
20
|
+
|
|
21
|
+
rpc BeginTransaction(BeginTransactionRequest) returns (TransactionHandle);
|
|
22
|
+
rpc TxPut(TxWriteRequest) returns (TxWriteResponse);
|
|
23
|
+
rpc TxPatch(TxWriteRequest) returns (TxWriteResponse);
|
|
24
|
+
rpc TxDelete(TxWriteRequest) returns (TxWriteResponse);
|
|
25
|
+
rpc TxQuery(TxQueryRequest) returns (stream QueryResultChunk);
|
|
26
|
+
rpc CommitTransaction(CommitTransactionRequest) returns (UnitOfWorkResult);
|
|
27
|
+
rpc RollbackTransaction(TransactionHandle) returns (RollbackResponse);
|
|
28
|
+
|
|
29
|
+
rpc CreateTable(CreateTableRequest) returns (Empty);
|
|
30
|
+
rpc DropField(DropFieldRequest) returns (Empty);
|
|
31
|
+
rpc DeclareIndex(DeclareIndexRequest) returns (Empty);
|
|
32
|
+
rpc DeclareTrigger(DeclareTriggerRequest) returns (Empty);
|
|
33
|
+
|
|
34
|
+
rpc TableNames(SessionRequest) returns (TableNamesResponse);
|
|
35
|
+
rpc DescribeTable(DescribeTableRequest) returns (DescribeTableResponse);
|
|
36
|
+
rpc Relations(RelationsRequest) returns (RelationsResponse);
|
|
37
|
+
rpc CheckIntegrity(SessionRequest) returns (IntegrityReport);
|
|
38
|
+
rpc Compact(CompactRequest) returns (CompactResponse);
|
|
39
|
+
rpc Checkpoint(CheckpointRequest) returns (Empty);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
message Empty {}
|
|
43
|
+
|
|
44
|
+
// A request carrying only the session that already opened a database — no other arguments.
|
|
45
|
+
message SessionRequest {
|
|
46
|
+
string client_id = 1;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
message OpenRequest {
|
|
50
|
+
// Filesystem path to the database directory, resolved on the server.
|
|
51
|
+
string database_dir = 1;
|
|
52
|
+
// Field 2 was `api_version`: the handshake now travels as the `x-hayson-api-version` metadata
|
|
53
|
+
// key on every request, checked by an interceptor, not as a field of this one message.
|
|
54
|
+
reserved 2;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
message OpenResponse {
|
|
58
|
+
// Handle for every subsequent RPC on this database session.
|
|
59
|
+
string client_id = 1;
|
|
60
|
+
// Field 2 was `api_version` — see OpenRequest. A refusal carries the server's version as
|
|
61
|
+
// `x-hayson-api-version` metadata on the status instead.
|
|
62
|
+
reserved 2;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
message CloseRequest {
|
|
66
|
+
string client_id = 1;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
message CloseResponse {}
|
|
70
|
+
|
|
71
|
+
message PutRequest {
|
|
72
|
+
string client_id = 1;
|
|
73
|
+
string table = 2;
|
|
74
|
+
google.protobuf.Struct document = 3;
|
|
75
|
+
bool force = 4;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
message PatchRequest {
|
|
79
|
+
string client_id = 1;
|
|
80
|
+
string table = 2;
|
|
81
|
+
string key = 3;
|
|
82
|
+
google.protobuf.Struct changes = 4;
|
|
83
|
+
bool force = 5;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
message DeleteRequest {
|
|
87
|
+
string client_id = 1;
|
|
88
|
+
string table = 2;
|
|
89
|
+
string key = 3;
|
|
90
|
+
bool force = 4;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
message WriteResponse {
|
|
94
|
+
google.protobuf.Struct record = 1;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
message GetRequest {
|
|
98
|
+
string client_id = 1;
|
|
99
|
+
string table = 2;
|
|
100
|
+
string key = 3;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
message GetResponse {
|
|
104
|
+
optional google.protobuf.Struct record = 1;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
message QueryRequest {
|
|
108
|
+
string client_id = 1;
|
|
109
|
+
string table = 2;
|
|
110
|
+
// A QuerySpec/PredicateNode tree serialized as JSON by serde_json, deserialized server-side —
|
|
111
|
+
// see the ADR/report for why this repo did not mirror the whole predicate tree in proto.
|
|
112
|
+
string predicate_json = 3;
|
|
113
|
+
// Records per streamed chunk; 0 lets the server pick its own default batch size.
|
|
114
|
+
uint32 chunk_size = 4;
|
|
115
|
+
// Matches to skip before the first returned record; 0 means no offset.
|
|
116
|
+
uint32 offset = 5;
|
|
117
|
+
// Maximum matches to return after the offset. Absent means no limit; a present 0 asks for
|
|
118
|
+
// no records, the meaning hayson-engine's query planner gives a limit of zero.
|
|
119
|
+
optional uint32 limit = 6;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
message QueryResultChunk {
|
|
123
|
+
repeated google.protobuf.Struct records = 1;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
message AggregateRequest {
|
|
127
|
+
string client_id = 1;
|
|
128
|
+
string table = 2;
|
|
129
|
+
string predicate_json = 3;
|
|
130
|
+
// count/sum/avg/min/max/group_by, serialized the same way as predicate_json.
|
|
131
|
+
string aggregate_json = 4;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
message AggregateResponse {
|
|
135
|
+
// AggregateResult or GroupedAggregateResult, serialized as JSON.
|
|
136
|
+
string result_json = 1;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
message BeginTransactionRequest {
|
|
140
|
+
string client_id = 1;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
message TransactionHandle {
|
|
144
|
+
string transaction_id = 1;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Commit of a unit of work. `idempotency_key` is what makes the commit retryable: the server
|
|
148
|
+
// remembers the outcome of a recent commit under its key and answers a repeat of that key with
|
|
149
|
+
// the very same outcome instead of applying the unit of work twice.
|
|
150
|
+
message CommitTransactionRequest {
|
|
151
|
+
string transaction_id = 1;
|
|
152
|
+
// Client-generated, unique per unit of work. Empty opts out of deduplication: the commit is
|
|
153
|
+
// applied and answered as it was before this field existed.
|
|
154
|
+
string idempotency_key = 2;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
enum TxOp {
|
|
158
|
+
TX_OP_UNSPECIFIED = 0;
|
|
159
|
+
TX_OP_PUT = 1;
|
|
160
|
+
TX_OP_PATCH = 2;
|
|
161
|
+
TX_OP_DELETE = 3;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
message TxWriteRequest {
|
|
165
|
+
string transaction_id = 1;
|
|
166
|
+
string table = 2;
|
|
167
|
+
TxOp op = 3;
|
|
168
|
+
// Required for TX_OP_PATCH and TX_OP_DELETE, ignored for TX_OP_PUT.
|
|
169
|
+
optional string key = 4;
|
|
170
|
+
// Required for TX_OP_PUT and TX_OP_PATCH.
|
|
171
|
+
google.protobuf.Struct document = 5;
|
|
172
|
+
bool force = 6;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
message TxWriteResponse {
|
|
176
|
+
optional google.protobuf.Struct record = 1;
|
|
177
|
+
// Set only for TX_OP_DELETE — whether the key existed before the delete.
|
|
178
|
+
optional bool existed = 2;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
message TxQueryRequest {
|
|
182
|
+
string transaction_id = 1;
|
|
183
|
+
string table = 2;
|
|
184
|
+
string predicate_json = 3;
|
|
185
|
+
uint32 chunk_size = 4;
|
|
186
|
+
// Matches to skip before the first returned record; 0 means no offset.
|
|
187
|
+
uint32 offset = 5;
|
|
188
|
+
// Maximum matches to return after the offset. Absent means no limit; a present 0 asks for
|
|
189
|
+
// no records, the meaning hayson-engine's query planner gives a limit of zero.
|
|
190
|
+
optional uint32 limit = 6;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
message UnitOfWorkResult {
|
|
194
|
+
uint32 operations = 1;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
message RollbackResponse {}
|
|
198
|
+
|
|
199
|
+
message CreateTableRequest {
|
|
200
|
+
string client_id = 1;
|
|
201
|
+
string table = 2;
|
|
202
|
+
// A TableSchema spec, in the same JSON shape `hayson-engine::schema::parse_schema` accepts.
|
|
203
|
+
string schema_json = 3;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
message DropFieldRequest {
|
|
207
|
+
string client_id = 1;
|
|
208
|
+
string table = 2;
|
|
209
|
+
string field = 3;
|
|
210
|
+
bool force = 4;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
message DeclareIndexRequest {
|
|
214
|
+
string client_id = 1;
|
|
215
|
+
string table = 2;
|
|
216
|
+
string index_json = 3;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
message DeclareTriggerRequest {
|
|
220
|
+
string client_id = 1;
|
|
221
|
+
string trigger_json = 2;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
message TableNamesResponse {
|
|
225
|
+
// Names of the tables the session serves, sorted, as a JSON array of strings.
|
|
226
|
+
string names_json = 1;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
message DescribeTableRequest {
|
|
230
|
+
string client_id = 1;
|
|
231
|
+
string table = 2;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
message DescribeTableResponse {
|
|
235
|
+
// The schema of one table as a standalone document, the same JSON shape
|
|
236
|
+
// CreateTableRequest.schema_json accepts back.
|
|
237
|
+
string schema_json = 1;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
message RelationsRequest {
|
|
241
|
+
string client_id = 1;
|
|
242
|
+
optional string table = 2;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
message RelationsResponse {
|
|
246
|
+
// Relation entries, serialized as JSON.
|
|
247
|
+
string relations_json = 1;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
message IntegrityReport {
|
|
251
|
+
string report_json = 1;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
message CompactRequest {
|
|
255
|
+
string client_id = 1;
|
|
256
|
+
optional string table = 2;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
message CompactResponse {
|
|
260
|
+
string result_json = 1;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
message CheckpointRequest {
|
|
264
|
+
string client_id = 1;
|
|
265
|
+
optional string table = 2;
|
|
266
|
+
}
|