@tdxvolt/volt-client-grpc 0.18.7 → 0.18.9

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/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.18.7",
6
+ "version": "0.18.9",
7
7
  "description": "tdx Volt library for nodejs clients",
8
8
  "type": "module",
9
9
  "exports": {
package/src/constants.js CHANGED
@@ -15,6 +15,7 @@ export const constants = {
15
15
  sqliteDatabaseAPI: "tdx.volt_api.data.v1.SqliteDatabaseAPI",
16
16
  ssiAPI: "tdx.volt_api.volt.v1.SsiAPI",
17
17
  relayAPI: "tdx.volt_api.relay.v1.RelayAPI",
18
+ syncAPI: "tdx.volt_api.volt.v1.SyncAPI",
18
19
  terminalAPI: "tdx.volt_api.volt.v1.TerminalAPI",
19
20
  voltAPI: "tdx.volt_api.volt.v1.VoltAPI",
20
21
  wireAPI: "tdx.volt_api.volt.v1.WireAPI"
package/src/grpc-call.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable no-underscore-dangle */
2
+ import { voltUtils as voltClientUtils } from "@tdxvolt/volt-client-web/js";
2
3
  import debug from "debug";
3
4
  import EventEmitter from "events";
4
- import { voltUtils as voltClientUtils } from "@tdxvolt/volt-client-web/js";
5
5
 
6
6
  const {
7
7
  aesCreateKey,
@@ -328,6 +328,7 @@ export default class GRPCCall extends EventEmitter {
328
328
  this._keyExchangePending = false;
329
329
  this._pendingRequests = [];
330
330
  this._encryptionKey = null;
331
+ this._ended = false;
331
332
  }
332
333
 
333
334
  start(grpcClient, request, unary = false) {
@@ -360,6 +361,11 @@ export default class GRPCCall extends EventEmitter {
360
361
  );
361
362
 
362
363
  this._call.on("data", (streamResponse) => {
364
+ if (this._ended) {
365
+ log("ignoring data after end on %s", this._methodName);
366
+ return;
367
+ }
368
+
363
369
  try {
364
370
  const parsedResponse = _parseResponse.call(
365
371
  this,
@@ -454,6 +460,7 @@ export default class GRPCCall extends EventEmitter {
454
460
 
455
461
  end() {
456
462
  if (this._call) {
463
+ this._ended = true;
457
464
  return this._call.end();
458
465
  } else {
459
466
  throw new Error("call not initialised");
@@ -1,8 +1,8 @@
1
1
  import debug from "debug";
2
2
  import protobuf from "protobufjs";
3
+ import { constants } from "./constants.js";
3
4
  import { createPackageDefinition } from "./proto-package-definition.js";
4
5
  import { voltProtos } from "./volt-proto-literals.js";
5
- import { constants } from "./constants.js";
6
6
 
7
7
  const log = debug("volt-client-grpc:proto-utils");
8
8
 
@@ -12,6 +12,7 @@ const voltServices = [
12
12
  constants.serviceType.sqliteDatabaseAPI,
13
13
  constants.serviceType.sqliteServerAPI,
14
14
  constants.serviceType.ssiAPI,
15
+ constants.serviceType.syncAPI,
15
16
  constants.serviceType.relayAPI,
16
17
  constants.serviceType.terminalAPI,
17
18
  constants.serviceType.wireAPI
@@ -56,4 +57,5 @@ function getBuiltInServiceDescriptors() {
56
57
  return getServiceDescriptors(voltServicePlaceholder);
57
58
  }
58
59
 
59
- export { getServiceDescriptors, getBuiltInServiceDescriptors };
60
+ export { getBuiltInServiceDescriptors, getServiceDescriptors };
61
+
@@ -1,20 +1,18 @@
1
1
  import debug from "debug";
2
2
  import EventEmitter from "events";
3
- import { VoltCredential } from "./volt-credential.js";
3
+ import fs from "fs";
4
4
  import path from "path";
5
- import { getServiceDescriptors } from "./proto-utils.js";
6
- import { createClient as createGrpcClient } from "./grpc-utils.js";
5
+ import GRPCCall from "./grpc-call.js";
7
6
  import {
8
7
  authenticateInternal,
9
8
  connectInternal,
10
9
  fetchVoltConfig,
11
10
  fetchVoltConfigFromDID,
12
11
  getVoltAPIClientInternal,
13
- unaryCallInternal,
14
- streamingCallInternal
12
+ streamingCallInternal,
13
+ unaryCallInternal
15
14
  } from "./volt-client-internal.js";
16
- import fs from "fs";
17
- import GRPCCall from "./grpc-call.js";
15
+ import { VoltCredential } from "./volt-credential.js";
18
16
 
19
17
  const { readFile } = fs.promises;
20
18
  const log = debug("volt-client-grpc:volt-client");
@@ -99,9 +97,7 @@ export class VoltClient extends EventEmitter {
99
97
  log("Attempt to load config from file %s", configPath);
100
98
  try {
101
99
  if (fs.existsSync(configPath)) {
102
- const configContents = await readFile(
103
- new URL(configPath, import.meta.url)
104
- );
100
+ const configContents = await readFile(configPath);
105
101
  configJSON = JSON.parse(configContents);
106
102
  } else {
107
103
  // There is currently no file at the given configuration path.
@@ -668,4 +664,15 @@ export class VoltClient extends EventEmitter {
668
664
  );
669
665
  return subscribeCall.start(grpcClient, request);
670
666
  }
667
+
668
+ SyncDocument(request) {
669
+ const grpcClient = this.getVoltAPIClient();
670
+
671
+ const syncDocumentCall = new GRPCCall(
672
+ this,
673
+ "SyncDocument",
674
+ "METHOD_TYPE_BIDI"
675
+ );
676
+ return syncDocumentCall.start(grpcClient, request);
677
+ }
671
678
  }
@@ -252,6 +252,63 @@ message CreateDatabaseResponse {
252
252
  }
253
253
 
254
254
  `;
255
+ export const proto_db_sync = `syntax = "proto3";
256
+
257
+ package tdx.volt_api.proto_db_sync.v1;
258
+
259
+ // Wraps arbitrary protobuf messages, with an index into the \`ProtobufSyncConfigurationHeader\` to indicate the specific message type this message wraps.
260
+ message ProtobufSyncWrapper {
261
+ oneof header_lookup {
262
+ // The index number of the header for this message type in the Volt logger configuration file.
263
+ uint32 header_index = 1;
264
+
265
+ // The name of the header for this message type, will be used to lookup against the \`id\` field in \`ProtobufSyncConfiguration\`.
266
+ // This will incur an overhead in terms of the packet size, but might be preferrable if volume is low or managing the header index is difficult.
267
+ string header_id = 2;
268
+ }
269
+
270
+ // The message payload, in serialised protobuf binary format.
271
+ // n.b. the serialisation should **not** be length-prefixed.
272
+ bytes payload = 3;
273
+ }
274
+
275
+ // Describes a single message type.
276
+ // A set of one or more of these messages is specified in \`ProtobufSyncConfigurationHeader\`.
277
+ message ProtobufSyncConfiguration {
278
+ // Optional id to associate with this configuration.
279
+ // This can be used in the \`header_id\` field of \`ProtobufSyncWrapper\` above to reference the configuration.
280
+ // If omitted the numerical index of the configuration in \`ProtobufSyncConfigurationHeader\` will be used instead.
281
+ string id = 1;
282
+
283
+ // The actual protobuf definition text.
284
+ // Copy and paste the source protobuf definition from the \`.proto\` file.
285
+ // Only simple protobuf structures are currently supported, e.g. no imports from other packages etc.
286
+ string message_proto = 2;
287
+
288
+ // The name of the message within \`message_proto\` above that represents the data to be sync'd, e.g. \`TCPDumpPacket\`.
289
+ string message_name = 3;
290
+
291
+ // The name of the table within the target database into which the message data for this type should be written.
292
+ string table_name = 4;
293
+ }
294
+
295
+ // This message is written at the beginning of every file to be ingested using the \`protoDbSync\` utility.
296
+ // It contains a \`header\` entry for each message type that may appear in the file.
297
+ // If the \`volt logger\` command is used, it will create this header automatically based on the configuration it's given.
298
+ message ProtobufSyncConfigurationHeader {
299
+ // This should ideally be a persistent UUID, at minimum it must be unique within the set of types of file any given instance of \`protoDbSync\` is processing in a given folder.
300
+ // It is used to match up orphaned or split packets that might occur when receiving data from a wire, for example, if a log file is rotated midway through a packet arriving on the wire.
301
+ // This id should persist for the life time of the set of data it describes, i.e. if a wire publication is stopped and restarted at some later point, the same id should be used if possible.
302
+ string id = 1;
303
+
304
+ // The set of possible configurations that can appear in any given protobuf sync data file.
305
+ // A serialised instance of this message must appear at the top of each data file.
306
+ // Each subsequent serialised message in the data file must be an instance of \`ProtobufSyncWrapper\`, and the \`header_lookup\` field refers to an entry in this list.
307
+ repeated ProtobufSyncConfiguration configuration = 2;
308
+
309
+ // Optional maximum size of the serialised messages, this doesn't need to be exact and the default is 64K if omitted.
310
+ int32 maximum_message_size = 3;
311
+ }`;
255
312
  export const proxy_api = `syntax = "proto3";
256
313
 
257
314
  package tdx.volt_api.relay.v1;
@@ -340,63 +397,6 @@ message TunnelResponse {
340
397
  }
341
398
  }
342
399
  `;
343
- export const sync = `syntax = "proto3";
344
-
345
- package tdx.volt_api.sync.v1;
346
-
347
- // Wraps arbitrary protobuf messages, with an index into the \`ProtobufSyncConfigurationHeader\` to indicate the specific message type this message wraps.
348
- message ProtobufSyncWrapper {
349
- oneof header_lookup {
350
- // The index number of the header for this message type in the Volt logger configuration file.
351
- uint32 header_index = 1;
352
-
353
- // The name of the header for this message type, will be used to lookup against the \`id\` field in \`ProtobufSyncConfiguration\`.
354
- // This will incur an overhead in terms of the packet size, but might be preferrable if volume is low or managing the header index is difficult.
355
- string header_id = 2;
356
- }
357
-
358
- // The message payload, in serialised protobuf binary format.
359
- // n.b. the serialisation should **not** be length-prefixed.
360
- bytes payload = 3;
361
- }
362
-
363
- // Describes a single message type.
364
- // A set of one or more of these messages is specified in \`ProtobufSyncConfigurationHeader\`.
365
- message ProtobufSyncConfiguration {
366
- // Optional id to associate with this configuration.
367
- // This can be used in the \`header_id\` field of \`ProtobufSyncWrapper\` above to reference the configuration.
368
- // If omitted the numerical index of the configuration in \`ProtobufSyncConfigurationHeader\` will be used instead.
369
- string id = 1;
370
-
371
- // The actual protobuf definition text.
372
- // Copy and paste the source protobuf definition from the \`.proto\` file.
373
- // Only simple protobuf structures are currently supported, e.g. no imports from other packages etc.
374
- string message_proto = 2;
375
-
376
- // The name of the message within \`message_proto\` above that represents the data to be sync'd, e.g. \`TCPDumpPacket\`.
377
- string message_name = 3;
378
-
379
- // The name of the table within the target database into which the message data for this type should be written.
380
- string table_name = 4;
381
- }
382
-
383
- // This message is written at the beginning of every file to be ingested using the \`protoDbSync\` utility.
384
- // It contains a \`header\` entry for each message type that may appear in the file.
385
- // If the \`volt logger\` command is used, it will create this header automatically based on the configuration it's given.
386
- message ProtobufSyncConfigurationHeader {
387
- // This should ideally be a persistent UUID, at minimum it must be unique within the set of types of file any given instance of \`protoDbSync\` is processing in a given folder.
388
- // It is used to match up orphaned or split packets that might occur when receiving data from a wire, for example, if a log file is rotated midway through a packet arriving on the wire.
389
- // This id should persist for the life time of the set of data it describes, i.e. if a wire publication is stopped and restarted at some later point, the same id should be used if possible.
390
- string id = 1;
391
-
392
- // The set of possible configurations that can appear in any given protobuf sync data file.
393
- // A serialised instance of this message must appear at the top of each data file.
394
- // Each subsequent serialised message in the data file must be an instance of \`ProtobufSyncWrapper\`, and the \`header_lookup\` field refers to an entry in this list.
395
- repeated ProtobufSyncConfiguration configuration = 2;
396
-
397
- // Optional maximum size of the serialised messages, this doesn't need to be exact and the default is 64K if omitted.
398
- int32 maximum_message_size = 3;
399
- }`;
400
400
  export const discovery_api = `syntax = "proto3";
401
401
 
402
402
  package tdx.volt_api.volt.v1;
@@ -1130,6 +1130,89 @@ message Status {
1130
1130
  string description = 3;
1131
1131
  }
1132
1132
  `;
1133
+ export const sync_api = `syntax = "proto3";
1134
+
1135
+ package tdx.volt_api.volt.v1;
1136
+
1137
+ import "tdx/volt_api/volt/v1/status.proto";
1138
+
1139
+ // The Sync API allows clients to collaboratively read and write JSON data to a shared resource.
1140
+ service SyncAPI {
1141
+ // Bidirectional streaming RPC for real-time document synchronization
1142
+ rpc SyncDocument(stream SyncDocumentRequest) returns (stream SyncDocumentResponse);
1143
+
1144
+ // Simple RPC to fetch current document state as JSON
1145
+ rpc GetDocumentJSON(GetDocumentJSONRequest) returns (GetDocumentJSONResponse);
1146
+ }
1147
+
1148
+ enum SyncState {
1149
+ SYNC_STATE_UNKNOWN = 0;
1150
+ SYNC_STATE_SYNCING = 1;
1151
+ SYNC_STATE_DONE = 2;
1152
+ SYNC_STATE_UPDATE = 3;
1153
+ }
1154
+
1155
+ message SyncDocumentStart {
1156
+ // The id of the database that contains the document.
1157
+ string database_id = 1;
1158
+
1159
+ // The id of the document to sync.
1160
+ string document_id = 2;
1161
+
1162
+ // The clients state vector. The Volt will respond with updates that should be applied to the local document.
1163
+ bytes state_vector = 3;
1164
+
1165
+ // Set to true to only receive updates from other clients.
1166
+ bool read_only = 4;
1167
+ }
1168
+
1169
+ message SyncDocumentUpdate {
1170
+ bytes chunk = 1;
1171
+
1172
+ bool complete = 2;
1173
+ }
1174
+
1175
+ message SyncDocumentRequest {
1176
+ oneof payload {
1177
+ // Initial sync configuration, must be sent as first message.
1178
+ SyncDocumentStart sync_start = 1;
1179
+
1180
+ // Updates to apply to the remote document.
1181
+ SyncDocumentUpdate update = 2;
1182
+ }
1183
+
1184
+ // The sync state of the local document
1185
+ SyncState sync_state = 3;
1186
+ }
1187
+
1188
+ message SyncDocumentResponse {
1189
+ // Details of any error that occurred on the call.
1190
+ tdx.volt_api.volt.v1.Status status = 1;
1191
+
1192
+ // The state vector of the Volt (remote) document. Only present in the initial response.
1193
+ bytes state_vector = 2;
1194
+
1195
+ // Updates to apply to client (local) document.
1196
+ SyncDocumentUpdate update = 3;
1197
+
1198
+ // The sync state of the Volt (remote) document
1199
+ SyncState sync_state = 4;
1200
+ }
1201
+
1202
+ message GetDocumentJSONRequest {
1203
+ string database_id = 1;
1204
+ string document_id = 2;
1205
+ }
1206
+
1207
+ message GetDocumentJSONResponse {
1208
+ oneof result {
1209
+ // Details of any error that occurred on the call.
1210
+ tdx.volt_api.volt.v1.Status error = 1;
1211
+
1212
+ // The current JSON snapshot of the document
1213
+ string json = 2;
1214
+ }
1215
+ }`;
1133
1216
  export const terminal_api = `syntax = "proto3";
1134
1217
 
1135
1218
  package tdx.volt_api.volt.v1;
@@ -2909,6 +2992,10 @@ message SignVerifyRequest {
2909
2992
  // Only valid if verifying.
2910
2993
  string digest_encoded = 5;
2911
2994
  }
2995
+
2996
+ // The DID of the identity used to sign or verify the message. If omitted, the authenticated identity will be used.
2997
+ // When signing, the authenticated identity must have volt:sign permission for the given DID.
2998
+ string identity_did = 6;
2912
2999
  }
2913
3000
 
2914
3001
  // Note that if verification was successful the response will be empty (there is no error and no digest is returned).
@@ -2973,7 +3060,7 @@ message SubscribeWireRequest {
2973
3060
  // One of the following fields will be present in the response.
2974
3061
  message SubscribeWireResponse {
2975
3062
  oneof payload {
2976
- // Details of any error that occured on the call.
3063
+ // Details of any error that occurred on the call.
2977
3064
  tdx.volt_api.volt.v1.Status status = 1;
2978
3065
 
2979
3066
  // Data received from the wire.
@@ -2982,4 +3069,4 @@ message SubscribeWireResponse {
2982
3069
  }
2983
3070
 
2984
3071
  `;
2985
- export const voltProtos = [sqlite, sqlite_database_api, sqlite_server_api, proxy_api, relay_api, sync, discovery_api, file, file_api, remote, spark_api, ssi, ssi_api, status, terminal_api, volt, volt_api, wire_api];
3072
+ export const voltProtos = [sqlite, sqlite_database_api, sqlite_server_api, proto_db_sync, proxy_api, relay_api, discovery_api, file, file_api, remote, spark_api, ssi, ssi_api, status, sync_api, terminal_api, volt, volt_api, wire_api];