@geodedb/client 1.0.2 → 1.3.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/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as tls from 'node:tls';
2
+ import { BinaryWriter, BinaryReader } from '@bufbuild/protobuf/wire';
2
3
  import { Decimal } from 'decimal.js-light';
3
4
  export { default as Decimal } from 'decimal.js-light';
4
5
 
@@ -73,12 +74,32 @@ interface GeodeConfig {
73
74
  keepAliveInterval?: number;
74
75
  /** Maximum idle time in milliseconds (default: 30000) */
75
76
  maxIdleTime?: number;
76
- /** Inline receive timeout in milliseconds (default: 5000) */
77
+ /**
78
+ * How long to wait for the data page the server sends inline after SCHEMA
79
+ * before falling back to an explicit PULL, in milliseconds (default: 5000).
80
+ * DSN key: `inline_timeout`.
81
+ *
82
+ * The inline response is never discarded when this deadline passes: the
83
+ * client keeps track of it and reconciles it with the PULL answer, so a slow
84
+ * first page can never leak into the next query (ENG-3916). Lower it only to
85
+ * make the client fall back to PULL sooner; `requestTimeout` still bounds
86
+ * the whole exchange.
87
+ */
77
88
  inlineTimeout?: number;
78
89
  /** Enable TLS for gRPC (default: true) */
79
90
  tls?: boolean;
80
91
  /** Graph name for DSN graph binding. When set, the server binds the session to this graph. */
81
92
  graph?: string;
93
+ /**
94
+ * Tenant identifier sent in the HELLO handshake (proto field 3). Required for
95
+ * multi-tenant deployments so the server scopes the session to this tenant.
96
+ */
97
+ tenant?: string;
98
+ /**
99
+ * FLE role sent in the HELLO handshake (proto field 8). Selects the
100
+ * field-level-encryption role for the session when set.
101
+ */
102
+ role?: string;
82
103
  }
83
104
  /**
84
105
  * Connection pool configuration.
@@ -122,6 +143,9 @@ declare function defaultConfig(): GeodeConfig;
122
143
  * - server_name: SNI server name
123
144
  * - connect_timeout: Connection timeout in ms
124
145
  * - request_timeout: Request timeout in ms
146
+ * - graph: Graph to bind the session to
147
+ * - tenant/tenant_id: Tenant identifier for multi-tenant deployments
148
+ * - role: FLE role for field-level access control
125
149
  *
126
150
  * Environment variables (used as defaults):
127
151
  * - GEODE_HOST: Default host
@@ -129,6 +153,8 @@ declare function defaultConfig(): GeodeConfig;
129
153
  * - GEODE_TLS_CA: Default CA certificate path
130
154
  * - GEODE_USERNAME: Default username
131
155
  * - GEODE_PASSWORD: Default password
156
+ * - GEODE_TENANT: Default tenant identifier
157
+ * - GEODE_ROLE: Default FLE role
132
158
  * - GEODE_TRANSPORT: Default transport type (quic or grpc)
133
159
  */
134
160
  declare function parseDSN(dsn: string): GeodeConfig;
@@ -140,6 +166,13 @@ declare function validateConfig(cfg: GeodeConfig): void;
140
166
  * Get the server address in host:port format.
141
167
  */
142
168
  declare function getAddress(cfg: GeodeConfig): string;
169
+ /**
170
+ * Serialise a GeodeConfig back to a DSN string. Inverse of parseDSN: only
171
+ * non-default values are emitted as query parameters to keep the DSN minimal.
172
+ * Credentials go in the userinfo segment when both username and password are
173
+ * present; a lone username uses userinfo, a lone password uses a `pass` param.
174
+ */
175
+ declare function formatDSN(cfg: GeodeConfig): string;
143
176
  /**
144
177
  * Clone configuration.
145
178
  */
@@ -275,6 +308,8 @@ declare class StateError extends Error implements GeodeError {
275
308
  * Connection state enumeration.
276
309
  */
277
310
  type ConnectionState = 'idle' | 'executing' | 'in_transaction' | 'fetching' | 'closed' | 'error';
311
+ declare const ERR_INVALID_IDENT_MESSAGE = "geode: identifier contains forbidden characters";
312
+ declare const ERR_INVALID_STRING_MESSAGE = "geode: string literal contains forbidden characters";
278
313
  declare const ERR_CLOSED_MESSAGE = "geode: connection closed";
279
314
  declare const ERR_QUERY_IN_PROGRESS_MESSAGE = "geode: query already in progress";
280
315
  declare const ERR_TX_IN_PROGRESS_MESSAGE = "geode: transaction already in progress";
@@ -282,13 +317,23 @@ declare const ERR_NO_TX_MESSAGE = "geode: no transaction in progress";
282
317
  declare const ERR_TX_DONE_MESSAGE = "geode: transaction already committed or rolled back";
283
318
  declare const ERR_ROWS_CLOSED_MESSAGE = "geode: rows closed";
284
319
  declare const ERR_BAD_CONN_MESSAGE = "geode: bad connection";
320
+ declare const ERR_NO_ROWS_MESSAGE = "geode: no rows in result set";
321
+ declare function ErrInvalidIdent(): Error;
322
+ declare function ErrInvalidString(): Error;
285
323
  declare function ErrClosed(): Error;
324
+ /**
325
+ * @deprecated No longer thrown by `Connection`. Concurrent requests on one
326
+ * connection are serialized on the connection's exchange lock instead of
327
+ * failing fast (ENG-3916). Kept exported so existing identity checks still
328
+ * compile.
329
+ */
286
330
  declare function ErrQueryInProgress(): Error;
287
331
  declare function ErrTxInProgress(): Error;
288
332
  declare function ErrNoTx(): Error;
289
333
  declare function ErrTxDone(): Error;
290
334
  declare function ErrRowsClosed(): Error;
291
335
  declare function ErrBadConn(): Error;
336
+ declare function ErrNoRows(): Error;
292
337
  /**
293
338
  * Check if an error is a specific sentinel error by message.
294
339
  */
@@ -305,282 +350,666 @@ declare function isGeodeError(err: unknown): err is GeodeError;
305
350
  * Check if an error is retryable.
306
351
  */
307
352
  declare function isRetryableError(err: unknown): boolean;
308
-
309
353
  /**
310
- * Geode Protobuf Wire Protocol
311
- *
312
- * Uses protobufjs for encoding/decoding protocol messages.
313
- * Wire format for QUIC: 4-byte Big Endian length prefix + protobuf message body.
354
+ * Reports whether `err` is a Geode authentication/authorization failure
355
+ * (GQL status class 28000 or the Geode-specific 08P01 password-reset
356
+ * extension). Returns false for null and for non-driver errors.
357
+ */
358
+ declare function isAuthError(err: unknown): boolean;
359
+ /**
360
+ * Reports whether `err` is a GQL parse/syntax error (status class 42000).
361
+ * Returns false for null and for non-driver errors.
362
+ */
363
+ declare function isSyntaxError(err: unknown): boolean;
364
+
365
+ declare enum IntKind {
366
+ INT_KIND_UNSPECIFIED = 0,
367
+ INT = 1,
368
+ SMALLINT = 2,
369
+ BIGINT = 3
370
+ }
371
+ declare enum FloatKind {
372
+ FLOAT_KIND_UNSPECIFIED = 0,
373
+ DOUBLE = 1,
374
+ REAL = 2
375
+ }
376
+ declare enum StringKind {
377
+ STRING_KIND_UNSPECIFIED = 0,
378
+ STRING = 1,
379
+ CHAR = 2,
380
+ VARCHAR = 3,
381
+ TEXT = 4
382
+ }
383
+ declare enum BytesKind {
384
+ BYTES_KIND_UNSPECIFIED = 0,
385
+ BYTEA = 1,
386
+ RAW = 2
387
+ }
388
+ /**
389
+ * ============================================================================
390
+ * QUIC Messages
391
+ * ============================================================================
392
+ */
393
+ interface QuicClientMessage {
394
+ hello?: HelloRequest | undefined;
395
+ execute?: ExecuteRequest | undefined;
396
+ pull?: PullRequest | undefined;
397
+ ping?: PingRequest | undefined;
398
+ cdcDiag?: CdcDiagnosticsRequest | undefined;
399
+ cdcCtrl?: CdcControlRequest | undefined;
400
+ begin?: BeginRequest | undefined;
401
+ commit?: CommitRequest | undefined;
402
+ rollback?: RollbackRequest | undefined;
403
+ savepoint?: SavepointRequest | undefined;
404
+ rollbackTo?: RollbackToRequest | undefined;
405
+ backup?: BackupRequest | undefined;
406
+ restore?: RestoreRequest | undefined;
407
+ uploadBackup?: UploadBackupRequest | undefined;
408
+ }
409
+ declare const QuicClientMessage: MessageFns<QuicClientMessage>;
410
+ interface QuicServerMessage {
411
+ hello?: HelloResponse | undefined;
412
+ execute?: ExecutionResponse | undefined;
413
+ pull?: PullResponse | undefined;
414
+ ping?: PingResponse | undefined;
415
+ cdcDiag?: CdcDiagnosticsResponse | undefined;
416
+ cdcCtrl?: CdcControlResponse | undefined;
417
+ begin?: BeginResponse | undefined;
418
+ commit?: CommitResponse | undefined;
419
+ rollback?: RollbackResponse | undefined;
420
+ savepoint?: SavepointResponse | undefined;
421
+ rollbackTo?: RollbackToResponse | undefined;
422
+ backup?: BackupResponse | undefined;
423
+ restore?: RestoreResponse | undefined;
424
+ uploadBackup?: UploadBackupResponse | undefined;
425
+ }
426
+ declare const QuicServerMessage: MessageFns<QuicServerMessage>;
427
+ /**
428
+ * ============================================================================
429
+ * Authentication (HELLO)
430
+ * ============================================================================
314
431
  */
315
432
  interface HelloRequest {
316
433
  username: string;
317
434
  password: string;
318
- tenantId?: string;
435
+ tenantId?: string | undefined;
319
436
  clientName: string;
320
437
  clientVersion: string;
321
438
  wantedConformance: string;
322
- graph?: string;
439
+ graph?: string | undefined;
440
+ /** FLE role for field-level access control */
441
+ role?: string | undefined;
323
442
  }
443
+ declare const HelloRequest: MessageFns<HelloRequest>;
324
444
  interface HelloResponse {
325
445
  success: boolean;
326
446
  sessionId: string;
327
447
  errorMessage: string;
328
448
  capabilities: string[];
329
- passwordResetRequired?: boolean;
330
- graph?: string;
331
- }
332
- interface Param {
333
- name: string;
334
- value: ProtoValue;
449
+ passwordResetRequired: boolean;
450
+ graph?: string | undefined;
335
451
  }
452
+ declare const HelloResponse: MessageFns<HelloResponse>;
453
+ /**
454
+ * ============================================================================
455
+ * Query Execution (RUN_GQL + PULL)
456
+ * ============================================================================
457
+ */
336
458
  interface ExecuteRequest {
337
459
  sessionId: string;
338
460
  query: string;
339
461
  params: Param[];
340
462
  }
463
+ declare const ExecuteRequest: MessageFns<ExecuteRequest>;
464
+ interface Param {
465
+ name: string;
466
+ value?: Value | undefined;
467
+ }
468
+ declare const Param: MessageFns<Param>;
341
469
  interface PullRequest {
342
- requestId: bigint | number;
470
+ requestId: bigint;
343
471
  pageSize: number;
472
+ /** Required for gRPC; ignored for QUIC */
344
473
  sessionId: string;
345
474
  }
475
+ declare const PullRequest: MessageFns<PullRequest>;
346
476
  interface PullResponse {
347
- response?: ExecutionResponse;
477
+ response?: ExecutionResponse | undefined;
348
478
  }
479
+ declare const PullResponse: MessageFns<PullResponse>;
480
+ /**
481
+ * ============================================================================
482
+ * Execution Responses
483
+ * ============================================================================
484
+ */
349
485
  interface Status {
486
+ /** e.g., "00000" */
350
487
  statusClass: string;
351
488
  statusSubclass: string;
352
489
  additionalStatuses: string[];
353
490
  flaggerFindings: string[];
354
491
  }
492
+ declare const Status: MessageFns<Status>;
493
+ interface ExecutionResponse {
494
+ status?: Status | undefined;
495
+ schema?: SchemaDefinition | undefined;
496
+ page?: DataPage | undefined;
497
+ error?: Error$1 | undefined;
498
+ metrics?: ExecutionMetrics | undefined;
499
+ explain?: ExplainPayload | undefined;
500
+ profile?: ProfilePayload | undefined;
501
+ heartbeat?: Heartbeat | undefined;
502
+ }
503
+ declare const ExecutionResponse: MessageFns<ExecutionResponse>;
504
+ interface SchemaDefinition {
505
+ columns: ColumnDefinition[];
506
+ }
507
+ declare const SchemaDefinition: MessageFns<SchemaDefinition>;
355
508
  interface ColumnDefinition {
356
509
  name: string;
357
510
  type: string;
358
511
  }
359
- interface SchemaDefinition {
360
- columns: ColumnDefinition[];
361
- }
362
- interface ProtoValue {
363
- nullVal?: NullValue;
364
- intVal?: IntValue;
365
- doubleVal?: DoubleValue;
366
- boolVal?: boolean;
367
- stringVal?: StringValue;
368
- decimalVal?: DecimalValue;
369
- bytesVal?: BytesValue;
370
- listVal?: ListValue;
371
- mapVal?: MapValue;
372
- nodeVal?: NodeValue;
373
- edgeVal?: EdgeValue;
374
- pathVal?: PathValue;
375
- extVal?: ExtendedValue;
512
+ declare const ColumnDefinition: MessageFns<ColumnDefinition>;
513
+ interface DataPage {
514
+ rows: Row$1[];
515
+ final: boolean;
516
+ ordered: boolean;
517
+ orderKeys: string[];
376
518
  }
519
+ declare const DataPage: MessageFns<DataPage>;
520
+ interface Row$1 {
521
+ values: Value[];
522
+ }
523
+ declare const Row$1: MessageFns<Row$1>;
524
+ /**
525
+ * ----------------------------------------------------------------------------
526
+ * Value Encoding
527
+ * ----------------------------------------------------------------------------
528
+ */
529
+ interface Value {
530
+ nullVal?: NullValue | undefined;
531
+ intVal?: IntValue | undefined;
532
+ doubleVal?: DoubleValue | undefined;
533
+ boolVal?: boolean | undefined;
534
+ stringVal?: StringValue | undefined;
535
+ decimalVal?: DecimalValue | undefined;
536
+ bytesVal?: BytesValue | undefined;
537
+ listVal?: ListValue | undefined;
538
+ mapVal?: MapValue | undefined;
539
+ nodeVal?: NodeValue | undefined;
540
+ edgeVal?: EdgeValue | undefined;
541
+ pathVal?: PathValue | undefined;
542
+ extVal?: ExtendedValue | undefined;
543
+ }
544
+ declare const Value: MessageFns<Value>;
377
545
  interface NullValue {
378
546
  }
547
+ declare const NullValue: MessageFns<NullValue>;
379
548
  interface IntValue {
380
- value: bigint | number;
381
- kind: number;
549
+ value: bigint;
550
+ kind: IntKind;
382
551
  }
552
+ declare const IntValue: MessageFns<IntValue>;
383
553
  interface DoubleValue {
384
554
  value: number;
385
- kind: number;
555
+ kind: FloatKind;
386
556
  }
557
+ declare const DoubleValue: MessageFns<DoubleValue>;
387
558
  interface StringValue {
388
559
  value: string;
389
- kind: number;
560
+ kind: StringKind;
390
561
  }
562
+ declare const StringValue: MessageFns<StringValue>;
391
563
  interface DecimalValue {
564
+ /** i128 as decimal string */
392
565
  coeff: string;
393
566
  scale: number;
394
567
  origScale: number;
395
568
  origRepr: string;
396
569
  }
570
+ declare const DecimalValue: MessageFns<DecimalValue>;
397
571
  interface BytesValue {
398
572
  value: Uint8Array;
399
- kind: number;
573
+ kind: BytesKind;
400
574
  }
575
+ declare const BytesValue: MessageFns<BytesValue>;
401
576
  interface ListValue {
402
- values: ProtoValue[];
577
+ values: Value[];
403
578
  }
579
+ declare const ListValue: MessageFns<ListValue>;
404
580
  interface MapEntry {
405
581
  key: string;
406
- value: ProtoValue;
582
+ value?: Value | undefined;
407
583
  }
584
+ declare const MapEntry: MessageFns<MapEntry>;
408
585
  interface MapValue {
409
586
  entries: MapEntry[];
410
587
  }
588
+ declare const MapValue: MessageFns<MapValue>;
411
589
  interface NodeValue {
412
- id: bigint | number;
590
+ id: bigint;
413
591
  labels: string[];
414
592
  properties: MapEntry[];
415
593
  }
594
+ declare const NodeValue: MessageFns<NodeValue>;
416
595
  interface EdgeValue {
417
- id: bigint | number;
418
- fromId: bigint | number;
419
- toId: bigint | number;
596
+ id: bigint;
597
+ fromId: bigint;
598
+ toId: bigint;
420
599
  label: string;
421
600
  properties: MapEntry[];
422
601
  }
602
+ declare const EdgeValue: MessageFns<EdgeValue>;
423
603
  interface PathValue {
424
604
  nodes: NodeValue[];
425
605
  edges: EdgeValue[];
426
606
  }
607
+ declare const PathValue: MessageFns<PathValue>;
427
608
  interface ExtendedValue {
428
609
  typeName: string;
429
- text?: string;
430
- bytes?: Uint8Array;
431
- intVal?: bigint | number;
432
- doubleVal?: number;
433
- boolVal?: boolean;
434
- }
435
- interface Row$1 {
436
- values: ProtoValue[];
437
- }
438
- interface DataPage {
439
- rows: Row$1[];
440
- final: boolean;
441
- ordered: boolean;
442
- orderKeys: string[];
443
- }
444
- interface ProtoError {
610
+ text?: string | undefined;
611
+ bytes?: Uint8Array | undefined;
612
+ intVal?: bigint | undefined;
613
+ doubleVal?: number | undefined;
614
+ boolVal?: boolean | undefined;
615
+ }
616
+ declare const ExtendedValue: MessageFns<ExtendedValue>;
617
+ interface Error$1 {
445
618
  code: string;
446
619
  message: string;
620
+ /** "ERROR" */
447
621
  type: string;
448
622
  anchor: string;
449
623
  }
624
+ declare const Error$1: MessageFns<Error$1>;
450
625
  interface ExecutionMetrics {
451
- parseDurationNs: bigint | number;
452
- planDurationNs: bigint | number;
453
- executeDurationNs: bigint | number;
454
- totalDurationNs: bigint | number;
455
- }
626
+ parseDurationNs: bigint;
627
+ planDurationNs: bigint;
628
+ executeDurationNs: bigint;
629
+ totalDurationNs: bigint;
630
+ }
631
+ declare const ExecutionMetrics: MessageFns<ExecutionMetrics>;
632
+ interface ExplainOp {
633
+ idx: number;
634
+ kind: string;
635
+ estRows: bigint;
636
+ cost: bigint;
637
+ }
638
+ declare const ExplainOp: MessageFns<ExplainOp>;
456
639
  interface ExplainTotals {
457
- cost?: number;
458
- est_rows?: number;
640
+ estRows: bigint;
641
+ cost: bigint;
459
642
  }
643
+ declare const ExplainTotals: MessageFns<ExplainTotals>;
644
+ interface ExplainProperties {
645
+ ordered: boolean;
646
+ limit: bigint;
647
+ offset: bigint;
648
+ distinct: boolean;
649
+ unionMode: string;
650
+ unionPartCount: number;
651
+ }
652
+ declare const ExplainProperties: MessageFns<ExplainProperties>;
653
+ interface ExplainCalibrationEntry {
654
+ idx: number;
655
+ estRows: number;
656
+ actualRows: number;
657
+ }
658
+ declare const ExplainCalibrationEntry: MessageFns<ExplainCalibrationEntry>;
659
+ interface ExplainCalibration {
660
+ mape: number;
661
+ entries: ExplainCalibrationEntry[];
662
+ }
663
+ declare const ExplainCalibration: MessageFns<ExplainCalibration>;
460
664
  interface ExplainPayload {
461
665
  schema: string;
462
- ops: unknown[];
463
- totals?: ExplainTotals;
464
- properties: unknown;
465
- calibration: unknown;
666
+ ops: ExplainOp[];
667
+ totals?: ExplainTotals | undefined;
668
+ properties?: ExplainProperties | undefined;
669
+ calibration?: ExplainCalibration | undefined;
466
670
  profileVersion: number;
467
671
  }
672
+ declare const ExplainPayload: MessageFns<ExplainPayload>;
673
+ interface ProfileOp {
674
+ op: string;
675
+ phase: string;
676
+ id: number;
677
+ opIndex: number;
678
+ inputRows: bigint;
679
+ rows: bigint;
680
+ timeNs: bigint;
681
+ cpuTimeNs: bigint;
682
+ bytesOut: bigint;
683
+ bytesAlloc: bigint;
684
+ estimateBytes: bigint;
685
+ estimateVsActual: bigint;
686
+ percentPeak: bigint;
687
+ percentNet: bigint;
688
+ cumulativeTimeNs: bigint;
689
+ freedBytes: bigint;
690
+ netAfterOp: bigint;
691
+ errorBytes: bigint;
692
+ errorAbsPct: bigint;
693
+ indexName: string;
694
+ selectivityEst: number;
695
+ }
696
+ declare const ProfileOp: MessageFns<ProfileOp>;
697
+ interface ProfilePeakContributor {
698
+ op: string;
699
+ bytesAlloc: bigint;
700
+ }
701
+ declare const ProfilePeakContributor: MessageFns<ProfilePeakContributor>;
702
+ interface ProfileTotals {
703
+ timeNs: bigint;
704
+ peakBytes: bigint;
705
+ }
706
+ declare const ProfileTotals: MessageFns<ProfileTotals>;
707
+ interface ProfileSpills {
708
+ sortSpills: bigint;
709
+ distinctSpills: bigint;
710
+ unionSpills: bigint;
711
+ spillReason: string;
712
+ peakBytesAtSpill: bigint;
713
+ firstSpillOpIndex: number;
714
+ }
715
+ declare const ProfileSpills: MessageFns<ProfileSpills>;
468
716
  interface ProfileMemory {
469
- netBytes?: number | bigint;
470
- peakBytes?: number | bigint;
471
- totalAllocBytes?: number | bigint;
717
+ netBytes: bigint;
718
+ peakBytes: bigint;
719
+ totalAllocBytes: bigint;
720
+ }
721
+ declare const ProfileMemory: MessageFns<ProfileMemory>;
722
+ interface ProfilePlannerEstimates {
723
+ sumEstimateBytes: bigint;
724
+ sumActualBytes: bigint;
725
+ countEstimatedOps: number;
726
+ minErrorAbsPct: number;
727
+ maxErrorAbsPct: number;
728
+ meanErrorAbsPct: number;
729
+ medianErrorAbsPct: number;
730
+ stddevErrorAbsPct: number;
731
+ adjustedEstimateFactor: number;
732
+ }
733
+ declare const ProfilePlannerEstimates: MessageFns<ProfilePlannerEstimates>;
734
+ interface ProfileMemCurvePoint {
735
+ opIndex: number;
736
+ netAfterOp: bigint;
737
+ }
738
+ declare const ProfileMemCurvePoint: MessageFns<ProfileMemCurvePoint>;
739
+ interface ProfileSetOp {
740
+ type: string;
741
+ mode: string;
742
+ inputRows: bigint;
743
+ outputRows: bigint;
744
+ hashDedupSize: bigint;
745
+ distinctFillPct: bigint;
472
746
  }
747
+ declare const ProfileSetOp: MessageFns<ProfileSetOp>;
473
748
  interface ProfilePayload {
474
749
  profileVersion: number;
475
- ops: unknown[];
476
- peakContributors: unknown[];
477
- totals: unknown;
478
- totalTimeNs: bigint | number;
479
- spills: unknown;
480
- memory?: ProfileMemory;
481
- plannerEstimates: unknown;
482
- memCurve: unknown[];
483
- setop: unknown;
484
- hashaggSpills: bigint | number;
750
+ ops: ProfileOp[];
751
+ peakContributors: ProfilePeakContributor[];
752
+ totals?: ProfileTotals | undefined;
753
+ totalTimeNs: bigint;
754
+ spills?: ProfileSpills | undefined;
755
+ memory?: ProfileMemory | undefined;
756
+ plannerEstimates?: ProfilePlannerEstimates | undefined;
757
+ memCurve: ProfileMemCurvePoint[];
758
+ setop?: ProfileSetOp | undefined;
759
+ hashaggSpills: bigint;
485
760
  hashaggSpillReason: string;
486
- committedTxns: bigint | number;
487
- graphStoreNodes: bigint | number;
488
- graphStoreEdges: bigint | number;
761
+ committedTxns: bigint;
762
+ graphStoreNodes: bigint;
763
+ graphStoreEdges: bigint;
489
764
  graphStoreDirty: boolean;
490
765
  flaggerFindings: string[];
491
766
  compact: boolean;
492
767
  }
768
+ declare const ProfilePayload: MessageFns<ProfilePayload>;
493
769
  interface Heartbeat {
494
770
  }
495
- interface ExecutionResponse {
496
- status?: Status;
497
- schema?: SchemaDefinition;
498
- page?: DataPage;
499
- error?: ProtoError;
500
- metrics?: ExecutionMetrics;
501
- explain?: ExplainPayload;
502
- profile?: ProfilePayload;
503
- heartbeat?: Heartbeat;
504
- }
771
+ declare const Heartbeat: MessageFns<Heartbeat>;
772
+ /**
773
+ * ============================================================================
774
+ * Utilities (PING)
775
+ * ============================================================================
776
+ */
505
777
  interface PingRequest {
506
778
  }
779
+ declare const PingRequest: MessageFns<PingRequest>;
507
780
  interface PingResponse {
508
781
  ok: boolean;
509
782
  }
783
+ declare const PingResponse: MessageFns<PingResponse>;
784
+ /**
785
+ * ============================================================================
786
+ * Transactions
787
+ * ============================================================================
788
+ */
510
789
  interface BeginRequest {
511
790
  readOnly: boolean;
791
+ /** Required for gRPC; ignored for QUIC */
512
792
  sessionId: string;
513
793
  }
794
+ declare const BeginRequest: MessageFns<BeginRequest>;
514
795
  interface BeginResponse {
515
796
  sessionId: string;
516
797
  txId: string;
517
798
  }
799
+ declare const BeginResponse: MessageFns<BeginResponse>;
518
800
  interface CommitRequest {
801
+ /** Required for gRPC; ignored for QUIC */
519
802
  sessionId: string;
520
803
  }
804
+ declare const CommitRequest: MessageFns<CommitRequest>;
521
805
  interface CommitResponse {
522
806
  success: boolean;
523
807
  }
808
+ declare const CommitResponse: MessageFns<CommitResponse>;
524
809
  interface RollbackRequest {
810
+ /** Required for gRPC; ignored for QUIC */
525
811
  sessionId: string;
526
812
  }
813
+ declare const RollbackRequest: MessageFns<RollbackRequest>;
527
814
  interface RollbackResponse {
528
815
  success: boolean;
529
816
  }
817
+ declare const RollbackResponse: MessageFns<RollbackResponse>;
530
818
  interface SavepointRequest {
531
819
  name: string;
820
+ /** Required for gRPC; ignored for QUIC */
532
821
  sessionId: string;
533
822
  }
823
+ declare const SavepointRequest: MessageFns<SavepointRequest>;
534
824
  interface SavepointResponse {
535
825
  success: boolean;
536
826
  }
827
+ declare const SavepointResponse: MessageFns<SavepointResponse>;
537
828
  interface RollbackToRequest {
538
829
  name: string;
830
+ /** Required for gRPC; ignored for QUIC */
539
831
  sessionId: string;
540
832
  }
833
+ declare const RollbackToRequest: MessageFns<RollbackToRequest>;
541
834
  interface RollbackToResponse {
542
835
  success: boolean;
543
836
  }
544
- interface QuicClientMessage {
545
- hello?: HelloRequest;
546
- execute?: ExecuteRequest;
547
- pull?: PullRequest;
548
- ping?: PingRequest;
549
- cdcDiag?: unknown;
550
- cdcCtrl?: unknown;
551
- begin?: BeginRequest;
552
- commit?: CommitRequest;
553
- rollback?: RollbackRequest;
554
- savepoint?: SavepointRequest;
555
- rollbackTo?: RollbackToRequest;
556
- backup?: unknown;
557
- restore?: unknown;
558
- uploadBackup?: unknown;
837
+ declare const RollbackToResponse: MessageFns<RollbackToResponse>;
838
+ /**
839
+ * ============================================================================
840
+ * CDC
841
+ * ============================================================================
842
+ */
843
+ interface CdcDiagnosticsRequest {
844
+ sessionId: string;
559
845
  }
560
- interface QuicServerMessage {
561
- hello?: HelloResponse;
562
- execute?: ExecutionResponse;
563
- pull?: PullResponse;
564
- ping?: PingResponse;
565
- cdcDiag?: unknown;
566
- cdcCtrl?: unknown;
567
- begin?: BeginResponse;
568
- commit?: CommitResponse;
569
- rollback?: RollbackResponse;
570
- savepoint?: SavepointResponse;
571
- rollbackTo?: RollbackToResponse;
572
- backup?: unknown;
573
- restore?: unknown;
574
- uploadBackup?: unknown;
846
+ declare const CdcDiagnosticsRequest: MessageFns<CdcDiagnosticsRequest>;
847
+ interface CdcDiagnosticsConfig {
848
+ enabled: boolean;
849
+ malformedSnapshotInterval: bigint;
850
+ malformedHashRetain: number;
851
+ malformedWarnPct: number;
852
+ malformedAbortPct: number;
853
+ flushIntervalMs: number;
854
+ batchSize: number;
855
+ pendingBackpressureWatermark: bigint;
856
+ }
857
+ declare const CdcDiagnosticsConfig: MessageFns<CdcDiagnosticsConfig>;
858
+ interface CdcDiagnosticsEngine {
859
+ isRunning: boolean;
860
+ lastFlushMs: bigint;
861
+ peakBuffer: bigint;
862
+ currentBuffer: bigint;
863
+ dynamicBatchSize: number;
864
+ batchAdjustments: number;
865
+ }
866
+ declare const CdcDiagnosticsEngine: MessageFns<CdcDiagnosticsEngine>;
867
+ interface CdcMalformedSnapshot {
868
+ count: bigint;
869
+ tsMs: bigint;
870
+ }
871
+ declare const CdcMalformedSnapshot: MessageFns<CdcMalformedSnapshot>;
872
+ interface CdcMalformedHash {
873
+ count: bigint;
874
+ hash: bigint;
875
+ tsMs: bigint;
876
+ prefixHex: string;
877
+ }
878
+ declare const CdcMalformedHash: MessageFns<CdcMalformedHash>;
879
+ interface CdcDiagnosticsResponse {
880
+ malformedChangeRecords: bigint;
881
+ totalChangeAttempts: bigint;
882
+ malformedRatio: number;
883
+ guardrailWarnTriggered: boolean;
884
+ guardrailAbortTriggered: boolean;
885
+ firstWarnTsMs: bigint;
886
+ firstAbortTsMs: bigint;
887
+ guardrailEpoch: bigint;
888
+ uptimeMs: bigint;
889
+ backpressure: boolean;
890
+ config?: CdcDiagnosticsConfig | undefined;
891
+ engine?: CdcDiagnosticsEngine | undefined;
892
+ malformedSnapshots: CdcMalformedSnapshot[];
893
+ malformedHashes: CdcMalformedHash[];
894
+ version: string;
895
+ timestampMs: bigint;
896
+ }
897
+ declare const CdcDiagnosticsResponse: MessageFns<CdcDiagnosticsResponse>;
898
+ interface CdcControlRequest {
899
+ action: string;
900
+ sessionId: string;
901
+ }
902
+ declare const CdcControlRequest: MessageFns<CdcControlRequest>;
903
+ interface CdcControlResponse {
904
+ success: boolean;
905
+ status: string;
906
+ guardrailEpoch: bigint;
907
+ }
908
+ declare const CdcControlResponse: MessageFns<CdcControlResponse>;
909
+ /**
910
+ * ============================================================================
911
+ * Backup / Restore
912
+ * ============================================================================
913
+ */
914
+ interface BackupRequest {
915
+ /** "full" */
916
+ backupType: string;
917
+ sessionId: string;
918
+ compress: boolean;
919
+ }
920
+ declare const BackupRequest: MessageFns<BackupRequest>;
921
+ interface BackupResponse {
922
+ success: boolean;
923
+ message: string;
924
+ backupId: string;
925
+ backupType: string;
926
+ sizeBytes: bigint;
927
+ compression: string;
928
+ checksum: string;
929
+ }
930
+ declare const BackupResponse: MessageFns<BackupResponse>;
931
+ interface RestoreRequest {
932
+ targetTime: string;
933
+ confirm: boolean;
934
+ sessionId: string;
575
935
  }
936
+ declare const RestoreRequest: MessageFns<RestoreRequest>;
937
+ interface RestoreResponse {
938
+ success: boolean;
939
+ message: string;
940
+ restoreDir: string;
941
+ targetTime: string;
942
+ restoreTimestamp: bigint;
943
+ }
944
+ declare const RestoreResponse: MessageFns<RestoreResponse>;
945
+ interface UploadBackupRequest {
946
+ sizeBytes: bigint;
947
+ checksum: string;
948
+ sessionId: string;
949
+ /**
950
+ * GAP-0880: full backup artifact bytes (GEOB header + payload). Required;
951
+ * metadata-only uploads are rejected by the server.
952
+ */
953
+ payload: Uint8Array;
954
+ }
955
+ declare const UploadBackupRequest: MessageFns<UploadBackupRequest>;
956
+ interface UploadBackupResponse {
957
+ success: boolean;
958
+ message: string;
959
+ uploadPath: string;
960
+ }
961
+ declare const UploadBackupResponse: MessageFns<UploadBackupResponse>;
962
+ type Builtin = Date | Function | Uint8Array | string | number | boolean | bigint | undefined;
963
+ type DeepPartial<T> = T extends Builtin ? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : T extends {} ? {
964
+ [K in keyof T]?: DeepPartial<T[K]>;
965
+ } : Partial<T>;
966
+ type KeysOfUnion<T> = T extends T ? keyof T : never;
967
+ type Exact<P, I extends P> = P extends Builtin ? P : P & {
968
+ [K in keyof P]: Exact<P[K], I[K]>;
969
+ } & {
970
+ [K in Exclude<keyof I, KeysOfUnion<P>>]: never;
971
+ };
972
+ interface MessageFns<T> {
973
+ encode(message: T, writer?: BinaryWriter): BinaryWriter;
974
+ decode(input: BinaryReader | Uint8Array, length?: number): T;
975
+ fromJSON(object: any): T;
976
+ toJSON(message: T): unknown;
977
+ create<I extends Exact<DeepPartial<T>, I>>(base?: I): T;
978
+ fromPartial<I extends Exact<DeepPartial<T>, I>>(object: I): T;
979
+ }
980
+
981
+ /**
982
+ * Geode Protobuf Wire Protocol
983
+ *
984
+ * Encoding/decoding of protocol messages using the protoc + ts-proto generated
985
+ * bindings (src/generated/geode.ts), which are produced from the canonical
986
+ * geode server proto. This eliminates proto drift: there are no longer any
987
+ * hand-written message interfaces, and the proto is no longer parsed at runtime
988
+ * via protobufjs.
989
+ *
990
+ * Wire format for QUIC: 4-byte Big Endian length prefix + protobuf message body.
991
+ *
992
+ * The public API (the build/encode/decode/value-conversion helpers and the
993
+ * exported types) is preserved exactly. Legacy type names that differ from the
994
+ * proto message names are aliased: the proto `Value` message is exported as
995
+ * `ProtoValue`, and the proto `Error` message as `ProtoError`.
996
+ */
997
+
998
+ /** A protobuf `Value` message (alias preserved for API stability). */
999
+ type ProtoValue = Value;
1000
+ /** A protobuf `Error` message (alias preserved for API stability). */
1001
+ type ProtoError = Error$1;
576
1002
  /**
577
1003
  * Initialize protobuf types synchronously.
578
- * Safe to call multiple times; only loads on first call.
579
- * Prefer ensureProtoInitialized() in async contexts to avoid blocking the event loop.
1004
+ *
1005
+ * No-op: bindings are generated at build time (protoc + ts-proto) and statically
1006
+ * imported, so no runtime initialization is required. Retained for API stability.
580
1007
  */
581
1008
  declare function initProtoSync(): void;
582
1009
  /**
583
1010
  * Ensure proto is initialized.
1011
+ *
1012
+ * No-op: see {@link initProtoSync}. Retained for API stability.
584
1013
  */
585
1014
  declare function ensureProtoInitialized(): Promise<void>;
586
1015
  /**
@@ -610,7 +1039,7 @@ declare function decodeLengthPrefix(data: Buffer): number;
610
1039
  /**
611
1040
  * Build a HelloRequest message.
612
1041
  */
613
- declare function buildHelloRequest(username: string, password: string, clientName: string, clientVersion: string, conformance: string, tenantId?: string, graph?: string): QuicClientMessage;
1042
+ declare function buildHelloRequest(username: string, password: string, clientName: string, clientVersion: string, conformance: string, tenantId?: string, graph?: string, role?: string): QuicClientMessage;
614
1043
  /**
615
1044
  * Build an ExecuteRequest message.
616
1045
  */
@@ -618,7 +1047,7 @@ declare function buildExecuteRequest(sessionId: string, query: string, params?:
618
1047
  /**
619
1048
  * Build a PullRequest message.
620
1049
  */
621
- declare function buildPullRequest(requestId: number, pageSize: number, sessionId: string): QuicClientMessage;
1050
+ declare function buildPullRequest(requestId: number | bigint, pageSize: number, sessionId: string): QuicClientMessage;
622
1051
  /**
623
1052
  * Build a PingRequest message.
624
1053
  */
@@ -709,6 +1138,25 @@ declare class QuicTransport extends BaseTransport {
709
1138
  private _maxBufferBytes;
710
1139
  private _pendingProtoReads;
711
1140
  private _pendingResponses;
1141
+ /**
1142
+ * Decode failure that arrived while no reader was parked. Surfaced by the
1143
+ * next receiveProto() once the already-decoded backlog has been drained.
1144
+ */
1145
+ private _pendingDecodeError;
1146
+ /**
1147
+ * Sticky failure latched when the read pump ends or throws. The pump is the
1148
+ * ONLY producer of responses, so once it is gone nothing can ever settle a
1149
+ * parked reader: report the failure instead of hanging (ENG-3918).
1150
+ */
1151
+ private _readFailure;
1152
+ /** True once close() has released the QUIC client and buffers. */
1153
+ private _disposed;
1154
+ /**
1155
+ * Serializes writes to the single bidirectional stream. `getWriter()` throws
1156
+ * "WritableStream is locked" while another write holds the lock, so queued
1157
+ * exchanges must take turns (ENG-3916).
1158
+ */
1159
+ private _writeChain;
712
1160
  constructor(address: string, maxMessageSize?: number, maxBufferBytes?: number);
713
1161
  /**
714
1162
  * Connect to the Geode server using QUIC.
@@ -718,6 +1166,15 @@ declare class QuicTransport extends BaseTransport {
718
1166
  * Start reading from the stream in the background.
719
1167
  */
720
1168
  private startReading;
1169
+ /**
1170
+ * Latch the transport dead after the read pump ends or throws.
1171
+ *
1172
+ * Nothing can produce a response once the pump is gone, so leaving
1173
+ * `isClosed()` false makes the connection (and the pool, whose only liveness
1174
+ * predicate is that flag) believe a dead socket is healthy, and parks every
1175
+ * later reader on a producer that will never run again (ENG-3918).
1176
+ */
1177
+ private failFromReadPump;
721
1178
  /**
722
1179
  * Reject all pending reads with an error.
723
1180
  */
@@ -998,6 +1455,10 @@ declare class QueryResult implements AsyncIterable<Row> {
998
1455
  private _closed;
999
1456
  private _bufferIndex;
1000
1457
  private _rowCount;
1458
+ /** Settles once the connection is back in phase after this result closed. */
1459
+ private _drained;
1460
+ /** Owner hook (used by the pool to hold its member for the result's life). */
1461
+ private _onCloseHooks;
1001
1462
  constructor(conn: Connection, columns: ColumnInfo[], initialRows: Record<string, unknown>[], final: boolean, ordered: boolean, orderKeys: string[], pageSize: number, signal?: AbortSignal);
1002
1463
  /**
1003
1464
  * Get column definitions.
@@ -1070,8 +1531,27 @@ declare class QueryResult implements AsyncIterable<Row> {
1070
1531
  reduce<T>(fn: (acc: T, row: Row, index: number) => T | Promise<T>, initial: T): Promise<T>;
1071
1532
  /**
1072
1533
  * Close the result set.
1534
+ *
1535
+ * When the server still owes pages, closing hands the connection the job of
1536
+ * draining them; use {@link QueryResult._settle} (or simply iterate to the
1537
+ * end) to await that. A caller that walks away never observes a connection
1538
+ * that is silently out of phase (ENG-3916).
1073
1539
  */
1074
1540
  close(): void;
1541
+ /**
1542
+ * @internal Whether the result still needs the connection.
1543
+ *
1544
+ * False once every page is buffered client-side: the connection is then free
1545
+ * and its pool member can be released immediately.
1546
+ */
1547
+ get _needsConnection(): boolean;
1548
+ /**
1549
+ * @internal Register a callback fired exactly once when this result closes.
1550
+ * Fires immediately when the result is already closed.
1551
+ */
1552
+ _onClose(hook: () => void): void;
1553
+ /** Close the result and wait for the connection to be back in phase. */
1554
+ private _settle;
1075
1555
  /**
1076
1556
  * Internal close (called by connection).
1077
1557
  */
@@ -1556,11 +2036,11 @@ declare function batchMap(conn: Connection, queryTemplate: string, items: QueryP
1556
2036
  * Unlike the sequential batch(), this executes multiple queries concurrently
1557
2037
  * up to the specified limit.
1558
2038
  *
1559
- * **Important:** A single `Connection` can only execute one query at a time
1560
- * (the connection state machine throws `ErrQueryInProgress` for concurrent
1561
- * queries). When a single connection is provided with concurrency > 1, this
1562
- * function automatically falls back to sequential execution (concurrency=1)
1563
- * to prevent runtime errors.
2039
+ * **Important:** A single `Connection` owns one bidirectional stream and can
2040
+ * only execute one query at a time; concurrent requests queue on its exchange
2041
+ * lock rather than overlapping (ENG-3916). When a single connection is
2042
+ * provided with concurrency > 1, this function falls back to sequential
2043
+ * execution (concurrency=1) because the extra concurrency buys nothing.
1564
2044
  *
1565
2045
  * For true parallel execution, use a connection pool or connection factory
1566
2046
  * that provides separate connections per concurrent query.
@@ -1610,6 +2090,21 @@ declare class Connection {
1610
2090
  private _requestId;
1611
2091
  private _sessionId;
1612
2092
  private _columns;
2093
+ private _delivery;
2094
+ /**
2095
+ * FIFO exchange lock.
2096
+ *
2097
+ * The connection owns ONE bidirectional stream and the wire protocol carries
2098
+ * no request/response correlation id, so two overlapping exchanges would read
2099
+ * each other's answers. Callers therefore queue instead of racing: an
2100
+ * exchange holds the lock for its FULL request -> final-response round trip,
2101
+ * and a streaming QueryResult keeps holding it until it is closed or drained
2102
+ * (ENG-3916).
2103
+ */
2104
+ private _exchangeHeld;
2105
+ private _exchangeWaiters;
2106
+ /** Lock release handed to the active streaming result, if any. */
2107
+ private _activeRelease;
1613
2108
  private constructor();
1614
2109
  /**
1615
2110
  * Create a new connection to the Geode server.
@@ -1629,12 +2124,27 @@ declare class Connection {
1629
2124
  get isClosed(): boolean;
1630
2125
  /** Get session ID. */
1631
2126
  get sessionId(): string;
2127
+ /**
2128
+ * Take the exchange lock, returning its (idempotent) release function.
2129
+ *
2130
+ * Registration is synchronous, so waiters are served strictly in call order.
2131
+ */
2132
+ private acquireExchange;
2133
+ /** Run one complete exchange under the connection's exchange lock. */
2134
+ private withExchange;
2135
+ /** Wake every queued exchange so it can observe the closed state. */
2136
+ private drainExchangeWaiters;
1632
2137
  /** Perform the HELLO handshake. */
1633
2138
  private hello;
1634
2139
  /** Execute a query that returns rows. */
1635
2140
  query(query: string, options?: QueryOptions): Promise<QueryResult>;
1636
2141
  /** Execute a query and return all rows as an array. */
1637
2142
  queryAll(query: string, options?: QueryOptions): Promise<Record<string, unknown>[]>;
2143
+ /**
2144
+ * Execute a query and return exactly the first row. Throws ErrNoRows when
2145
+ * the result set is empty, mirroring database/sql's ErrNoRows.
2146
+ */
2147
+ queryRow(query: string, options?: QueryOptions): Promise<Record<string, unknown>>;
1638
2148
  /** Execute a query that doesn't return rows. */
1639
2149
  exec(query: string, options?: QueryOptions): Promise<void>;
1640
2150
  /** @internal Fetch the next page of results. Called by QueryResult. */
@@ -1642,20 +2152,78 @@ declare class Connection {
1642
2152
  rows: Record<string, unknown>[];
1643
2153
  final: boolean;
1644
2154
  }>;
1645
- /** Try to receive an inline response with short timeout. */
2155
+ /**
2156
+ * Read the next page off the stream.
2157
+ *
2158
+ * Accepts either envelope: the server pushes pages as `execute` responses and
2159
+ * wraps a PULL's answer in `pull`. Anything else means the stream is out of
2160
+ * phase with the request being served, so the connection fails closed instead
2161
+ * of silently swallowing the message.
2162
+ */
2163
+ private _readNextPage;
2164
+ /**
2165
+ * Wait for the response the server sends after SCHEMA.
2166
+ *
2167
+ * Returns `null` when the inline deadline (`inlineTimeout`) expires. That
2168
+ * response is then STILL in flight - the caller must reconcile it before
2169
+ * returning, because the transport is a FIFO stream without request/response
2170
+ * correlation and anything left behind is read by the next request
2171
+ * (ENG-3916).
2172
+ */
1646
2173
  private _tryReceiveInline;
1647
- /** Read inline execute responses until a page, error, heartbeat, or timeout arrives. */
2174
+ /** Read inline execute responses until a page, error, heartbeat, or the inline deadline. */
1648
2175
  private _readInlineExecute;
1649
- /** Drain remaining data pages until final=true to prevent query corruption (QUAL-T7). */
2176
+ /**
2177
+ * Send a PULL and consume responses until every outstanding response has
2178
+ * been accounted for.
2179
+ *
2180
+ * The wire protocol is a FIFO stream with no request/response correlation
2181
+ * id, so the client must reconcile the whole exchange before it returns:
2182
+ * a response left in the transport is read by the NEXT request, which then
2183
+ * sees this query's schema and rows (ENG-3916). Up to two responses can be
2184
+ * outstanding here:
2185
+ *
2186
+ * - the inline page the server sends after SCHEMA, when the inline read
2187
+ * gave up waiting for it (`inlinePending`), and
2188
+ * - the answer to the PULL sent below, which QUIC servers always send as a
2189
+ * `pull`-wrapped message.
2190
+ *
2191
+ * Because the server writes its responses in order, a `pull`-wrapped answer
2192
+ * also proves that nothing is still coming for the EXECUTE, which is what
2193
+ * makes the reconciliation exact.
2194
+ *
2195
+ * When the exchange cannot be reconciled - a timeout, an abort or a
2196
+ * transport failure while a response is still owed - the connection is
2197
+ * closed instead of returned to the caller (and to the pool).
2198
+ *
2199
+ * NOTE (server team, ENG-3916): the durable fix is a request/response
2200
+ * correlation id in the proto. Until the wire protocol carries one, the
2201
+ * client can only reconcile by message type plus stream ordering.
2202
+ */
2203
+ private _pullFirstPage;
2204
+ /**
2205
+ * Drain remaining data pages until final=true to prevent query corruption
2206
+ * (QUAL-T7). Honours the current delivery mode: pushed pages are read,
2207
+ * parked results are pulled one page at a time.
2208
+ */
1650
2209
  private _drainRemainingPages;
1651
- /** @internal Release the active result, returning the connection to idle. */
1652
- _releaseResult(result: QueryResult): void;
2210
+ /**
2211
+ * @internal Release the active result, returning the connection to idle.
2212
+ *
2213
+ * A result abandoned before `final = true` leaves pages the server still owes
2214
+ * on the stream. They are drained here - under the exchange lock the result
2215
+ * still holds - so the next caller cannot read them as its own (ENG-3916).
2216
+ * The returned promise settles once the connection is back in phase.
2217
+ */
2218
+ _releaseResult(result: QueryResult, final: boolean): Promise<void>;
1653
2219
  /** Begin a transaction. */
1654
2220
  begin(signal?: AbortSignal): Promise<Transaction>;
1655
2221
  /** @internal Commit the current transaction. Called by Transaction. */
1656
2222
  _commit(signal?: AbortSignal): Promise<void>;
1657
2223
  /** @internal Rollback the current transaction. Called by Transaction. */
1658
2224
  _rollback(signal?: AbortSignal): Promise<void>;
2225
+ /** Send ROLLBACK and consume its answer. The exchange lock must be held. */
2226
+ private _rollbackExchange;
1659
2227
  /** @internal Create a named savepoint. Called by Transaction. */
1660
2228
  _savepoint(name: string, signal?: AbortSignal): Promise<void>;
1661
2229
  /** @internal Rollback to a previously created savepoint. Called by Transaction. */
@@ -1666,6 +2234,8 @@ declare class Connection {
1666
2234
  reset(signal?: AbortSignal): Promise<void>;
1667
2235
  /** Close the connection. */
1668
2236
  close(): Promise<void>;
2237
+ /** Drop the active result and hand its exchange lock back. */
2238
+ private _abandonActiveResult;
1669
2239
  /** Create a prepared statement. */
1670
2240
  prepare(query: string): Promise<PreparedStatement>;
1671
2241
  /** Get the query execution plan without executing. */
@@ -1674,7 +2244,12 @@ declare class Connection {
1674
2244
  profile(query: string, options?: ExplainOptions): Promise<QueryProfile>;
1675
2245
  /** Execute multiple queries in a batch. */
1676
2246
  batch(queries: BatchQuery[], options?: BatchOptions): Promise<BatchSummary>;
1677
- /** Check connection state before operation. */
2247
+ /**
2248
+ * Check connection state before operation.
2249
+ *
2250
+ * Concurrent requests are NOT rejected any more: they queue on the exchange
2251
+ * lock (ENG-3916). Only genuinely illegal states fail fast here.
2252
+ */
1678
2253
  private checkState;
1679
2254
  /** Send a protobuf message with request timeout enforcement. */
1680
2255
  private _sendWithTimeout;
@@ -1682,7 +2257,38 @@ declare class Connection {
1682
2257
  private _receiveWithTimeout;
1683
2258
  /** Create a combined abort signal from requestTimeout and optional caller signal (CWE-703). */
1684
2259
  private _withRequestTimeout;
2260
+ /**
2261
+ * Tear the connection down after a transport failure.
2262
+ *
2263
+ * `responseOwed` marks the cases where the server may still answer: a request
2264
+ * deadline that elapsed, or any aborted receive. Those leave the stream out
2265
+ * of phase, so the connection must not be reused (or returned to the pool)
2266
+ * even though the underlying socket is still open (ENG-3918).
2267
+ */
1685
2268
  private _closeOnTransportError;
2269
+ /**
2270
+ * Whether the server answers every PULL with its own message.
2271
+ *
2272
+ * QUIC servers reply to a PULL with a `pull`-wrapped response, so that
2273
+ * response has to be consumed before the connection is back in phase. The
2274
+ * gRPC transport has no PULL RPC: it serves PULLs from the Execute stream
2275
+ * that is already open, so no extra message is produced.
2276
+ */
2277
+ private get _pullIsAcknowledged();
2278
+ /**
2279
+ * Tear the connection down after a protocol desync and build the error.
2280
+ *
2281
+ * The stream carries no correlation ids, so a message that cannot belong to
2282
+ * the request being served means client and server are out of phase: every
2283
+ * later response would answer an earlier request, silently handing one
2284
+ * caller another caller's rows. Failing closed makes the connection
2285
+ * unusable, and the pool drops closed connections instead of reusing them.
2286
+ */
2287
+ private _protocolDesync;
2288
+ /** Close the transport and drop any active result, ignoring teardown errors. */
2289
+ private _forceClose;
2290
+ /** Return to the resting state, unless the connection was torn down. */
2291
+ private _restoreIdleState;
1686
2292
  }
1687
2293
 
1688
2294
  /**
@@ -2262,12 +2868,22 @@ declare class ConnectionPool {
2262
2868
  withConnection<T>(fn: (conn: Connection) => Promise<T>, signal?: AbortSignal): Promise<T>;
2263
2869
  /**
2264
2870
  * Execute a query using a pooled connection.
2871
+ *
2872
+ * A streaming result keeps fetching pages from the connection it was created
2873
+ * on, so the pooled member stays checked out until the result is closed
2874
+ * (ENG-3916). A result whose rows are already buffered needs nothing further
2875
+ * from the connection and releases the member right away.
2265
2876
  */
2266
2877
  query(query: string, options?: QueryOptions): Promise<QueryResult>;
2267
2878
  /**
2268
2879
  * Execute a query and return all rows.
2269
2880
  */
2270
2881
  queryAll(query: string, options?: QueryOptions): Promise<Record<string, unknown>[]>;
2882
+ /**
2883
+ * Execute a query using a pooled connection and return the first row.
2884
+ * Throws ErrNoRows when the result set is empty.
2885
+ */
2886
+ queryRow(query: string, options?: QueryOptions): Promise<Record<string, unknown>>;
2271
2887
  /**
2272
2888
  * Execute a statement that doesn't return rows.
2273
2889
  */
@@ -2288,6 +2904,17 @@ declare class ConnectionPool {
2288
2904
  * Add a new connection to the pool with rate limiting and exponential backoff.
2289
2905
  */
2290
2906
  private addConnection;
2907
+ /**
2908
+ * Drop every idle member whose connection is no longer usable.
2909
+ *
2910
+ * `Connection.isClosed` is the pool's only liveness predicate, and a
2911
+ * connection torn down after a desync reports closed: leaving those members
2912
+ * in place both risks reuse and starves the pool of its maxConnections slots
2913
+ * until the next maintenance tick (ENG-3918).
2914
+ */
2915
+ private evictBrokenConnections;
2916
+ /** Close a discarded connection, ignoring teardown failures. */
2917
+ private closeQuietly;
2291
2918
  /**
2292
2919
  * Remove a connection from the pool.
2293
2920
  */
@@ -2342,6 +2969,32 @@ declare function defaultRetryPolicy(): RetryPolicy;
2342
2969
  */
2343
2970
  declare function withRetry<T>(fn: () => Promise<T>, policy?: RetryPolicy): Promise<T>;
2344
2971
 
2972
+ /**
2973
+ * GQL Quoting Helpers
2974
+ *
2975
+ * Ports geode-client-go quote.go: safe inlining of identifiers, string
2976
+ * literals, and graph names into GQL admin statements.
2977
+ */
2978
+ /**
2979
+ * Return `name` stripped of any character that is not alphanumeric, underscore,
2980
+ * or hyphen, so it can be inlined safely into a USE GRAPH statement.
2981
+ */
2982
+ declare function sanitizeGraphName(name: string): string;
2983
+ /**
2984
+ * Validate and return `name` in a form safe to inline into a GQL admin
2985
+ * statement that takes an identifier. Valid identifiers consist of letters,
2986
+ * digits, underscore, and hyphen, and must not start with a hyphen. Digits are
2987
+ * permitted at any position. Throws ErrInvalidIdent for empty or invalid input.
2988
+ */
2989
+ declare function quoteIdent(name: string): string;
2990
+ /**
2991
+ * Return `s` wrapped in GQL single quotes with backslashes and single quotes
2992
+ * escaped. ASCII control characters (< 0x20 or 0x7F) are rejected with
2993
+ * ErrInvalidString. Escape order: backslash first (\ -> \\), then single
2994
+ * quotes (' -> '').
2995
+ */
2996
+ declare function quoteString(s: string): string;
2997
+
2345
2998
  /**
2346
2999
  * gRPC Transport Layer
2347
3000
  *
@@ -2882,4 +3535,97 @@ declare function node(): NodePatternBuilder;
2882
3535
  */
2883
3536
  declare function edge(): EdgePatternBuilder;
2884
3537
 
2885
- export { AuthClient, BaseTransport, type BatchOptions, type BatchQuery, type BatchResult, type BatchSummary, type BeginRequest, type BeginResponse, type ClientOptions, type ColumnDef, type ColumnDefinition, type ColumnInfo, type CommitRequest, type CommitResponse, ConfigError, Connection, ConnectionPool, type ConnectionState, type CreateRLSPolicyOptions, type CreateRoleOptions, type CreateUserOptions, DEFAULT_CONFORMANCE, DEFAULT_GRPC_PORT, DEFAULT_HELLO_NAME, DEFAULT_HELLO_VERSION, DEFAULT_PAGE_SIZE, DEFAULT_PORT, type DSNScheme, type DataPage, DriverError, ERR_BAD_CONN_MESSAGE, ERR_CLOSED_MESSAGE, ERR_NO_TX_MESSAGE, ERR_QUERY_IN_PROGRESS_MESSAGE, ERR_ROWS_CLOSED_MESSAGE, ERR_TX_DONE_MESSAGE, ERR_TX_IN_PROGRESS_MESSAGE, type EdgeDirection, type EdgePattern, EdgePatternBuilder, ErrBadConn, ErrClosed, ErrNoTx, ErrQueryInProgress, ErrRowsClosed, ErrTxDone, ErrTxInProgress, type ExecuteRequest, type ExecutionResponse, type ExplainOptions, type GQLEdge, type GQLId, type GQLNode, type GQLPath, type GQLRange, type GQLType, GQLValue, type GQLValueKind, GeodeClient, type GeodeConfig, type GeodeError, GrpcTransport, type HelloRequest, type HelloResponse, MAX_PAGE_SIZE, MAX_QUERY_LENGTH, MockTransport, type NodePattern, NodePatternBuilder, type OperationTiming, type Param, type ParameterInfo, PatternBuilder, type PatternElement, type Permission, type PingRequest, type PingResponse, type PlanOperation, type PoolConfig, PredicateBuilder, type PredicateOp, PreparedStatement, type ProtoError, type Row$1 as ProtoRow, type ProtoValue, type PullRequest, type PullResponse, QueryBuilder, type QueryOptions, type QueryParams, type QueryPlan, type QueryProfile, QueryResult, QueryResultIterator, type QuicClientMessage, type QuicServerMessage, QuicTransport, QuicTransport as QuicheTransport, type RLSPolicy, type RawEdge, type RetryPolicy, type Role, type RollbackRequest, type RollbackResponse, type Row, SUPPORTED_SCHEMES, type SchemaDefinition, SecurityError, type SortDirection, StateError, type Status, StatusClass, type StatusClassType, Transaction, type Transport, TransportError, type TransportType, type User, batch, batchAll, batchFirst, batchMap, batchParallel, buildBeginRequest, buildCommitRequest, buildExecuteRequest, buildHelloRequest, buildPingRequest, buildPullRequest, buildRollbackRequest, buildRollbackToRequest, buildSavepointRequest, buildTLSConfig, cloneConfig, createAuthClient, createClient, createClientWithConfig, createTransport, decodeLengthPrefix, decodeQuicServerMessage, defaultConfig, defaultRetryPolicy, edge, encodeQuicClientMessage, encodeWithLengthPrefix, ensureProtoInitialized, explain, extractParameters, formatPlan, formatProfile, fromJSON, getAddress, getProtoPath, initProtoSync, isDriverError, isGeodeError, isRetryableError, isSentinelError, jsToProtoValue, node, parseDSN, parseGQLType, parseRow, pattern, predicate, prepare, profile, protoValueToJS, query, redactConfig, redactDSN, rowToObject, rowToRecord, sanitizeForLog, validateConfig, validateHostname, validatePageSize, validateParamName, validateParamValue, validatePort, validateQuery, validateSavepointName, withRetry, withTransaction };
3538
+ /**
3539
+ * Schema Loading
3540
+ *
3541
+ * Ports geode-client-go schema.go: read .gql files from a directory and turn
3542
+ * them into Statements suitable for batchExec / pipelineExec.
3543
+ */
3544
+ /** A GQL query paired with optional bound parameters. */
3545
+ interface Statement {
3546
+ query: string;
3547
+ params?: Record<string, unknown>;
3548
+ }
3549
+ /**
3550
+ * Read all direct-child `.gql` files from `dir` and return Statements.
3551
+ *
3552
+ * Subdirectories are not traversed. Lines are split into statements at
3553
+ * semicolons after stripping blank lines, line comments (`//` and `--`), and
3554
+ * lines that do not start with a recognised GQL keyword.
3555
+ */
3556
+ declare function parseSchemaFS(dir: string): Promise<Statement[]>;
3557
+
3558
+ /**
3559
+ * Pipeline / Batch Execution (GAP-0900)
3560
+ *
3561
+ * Ports geode-client-go batch.go PipelineExec/BatchExec:
3562
+ * - batchExec runs all statements inside one transaction, with retry.
3563
+ * - pipelineExec splits into chunks and runs up to maxWorkers concurrently;
3564
+ * the first error stops launching new chunks while in-flight chunks finish.
3565
+ */
3566
+
3567
+ /** Default number of statements per chunk in pipelineExec. */
3568
+ declare const DEFAULT_CHUNK_SIZE = 100;
3569
+ /** Default maximum number of concurrent chunk workers in pipelineExec. */
3570
+ declare const DEFAULT_MAX_WORKERS = 8;
3571
+ /** Minimal transaction surface pipelineExec needs. */
3572
+ interface PipelineTx {
3573
+ exec(query: string, options?: {
3574
+ params?: Record<string, unknown>;
3575
+ }): Promise<void>;
3576
+ }
3577
+ /** Minimal pool surface pipelineExec needs (ConnectionPool satisfies this). */
3578
+ interface PipelineExecutor {
3579
+ withTransaction<T>(fn: (tx: PipelineTx) => Promise<T>): Promise<T>;
3580
+ }
3581
+ /**
3582
+ * Execute `stmts` inside a single transaction with automatic retry on
3583
+ * retryable errors. An empty list is a no-op.
3584
+ */
3585
+ declare function batchExec(pool: PipelineExecutor, stmts: Statement[]): Promise<void>;
3586
+ /**
3587
+ * Execute `stmts` in parallel chunks. Splits into chunks of `chunkSize` and
3588
+ * runs up to `maxWorkers` chunks concurrently; each chunk runs through
3589
+ * batchExec. Returns the first error encountered; once an error occurs no new
3590
+ * chunks are launched but in-flight chunks complete.
3591
+ */
3592
+ declare function pipelineExec(pool: PipelineExecutor, stmts: Statement[], opts?: {
3593
+ chunkSize?: number;
3594
+ maxWorkers?: number;
3595
+ signal?: AbortSignal;
3596
+ }): Promise<void>;
3597
+
3598
+ /**
3599
+ * Field-Level Encryption (FLE)
3600
+ *
3601
+ * Ports geode-client-go crypto/cipher.go using node:crypto:
3602
+ * - AES-256-GCM authenticated encryption (random 12-byte nonce, prepended).
3603
+ * - HKDF-SHA256 derives separate encryption and HMAC keys from a >= 32-byte
3604
+ * master key.
3605
+ * - HMAC-SHA256 hex digest for deterministic searchable encryption.
3606
+ */
3607
+ /** Holds derived encryption and HMAC keys for field-level encryption. */
3608
+ declare class GeodeCipher {
3609
+ private readonly encKey;
3610
+ private readonly hmacKey;
3611
+ /** @internal Use createCipher(). */
3612
+ constructor(masterKey: Uint8Array);
3613
+ /** Encrypt with AES-256-GCM, prepending a random nonce. */
3614
+ encrypt(plaintext: Uint8Array): Buffer;
3615
+ /** Decrypt a ciphertext produced by encrypt(). Throws on short input or auth failure. */
3616
+ decrypt(ciphertext: Uint8Array): Buffer;
3617
+ /** Encrypt a string, returning a base64-encoded result. */
3618
+ encryptString(plaintext: string): string;
3619
+ /** Base64-decode and decrypt, returning the original string. */
3620
+ decryptString(encoded: string): string;
3621
+ /**
3622
+ * Compute HMAC-SHA256 of `data` using the derived HMAC key, returning a
3623
+ * 64-char lowercase hex digest. Deterministic; use for equality lookups on
3624
+ * encrypted fields.
3625
+ */
3626
+ hmacHex(data: string): string;
3627
+ }
3628
+ /** Create a GeodeCipher from a master key (>= 32 bytes). */
3629
+ declare function createCipher(masterKey: Uint8Array): GeodeCipher;
3630
+
3631
+ export { AuthClient, BaseTransport, type BatchOptions, type BatchQuery, type BatchResult, type BatchSummary, BeginRequest, BeginResponse, type ClientOptions, type ColumnDef, ColumnDefinition, type ColumnInfo, CommitRequest, CommitResponse, ConfigError, Connection, ConnectionPool, type ConnectionState, type CreateRLSPolicyOptions, type CreateRoleOptions, type CreateUserOptions, DEFAULT_CHUNK_SIZE, DEFAULT_CONFORMANCE, DEFAULT_GRPC_PORT, DEFAULT_HELLO_NAME, DEFAULT_HELLO_VERSION, DEFAULT_MAX_WORKERS, DEFAULT_PAGE_SIZE, DEFAULT_PORT, type DSNScheme, DataPage, DriverError, ERR_BAD_CONN_MESSAGE, ERR_CLOSED_MESSAGE, ERR_INVALID_IDENT_MESSAGE, ERR_INVALID_STRING_MESSAGE, ERR_NO_ROWS_MESSAGE, ERR_NO_TX_MESSAGE, ERR_QUERY_IN_PROGRESS_MESSAGE, ERR_ROWS_CLOSED_MESSAGE, ERR_TX_DONE_MESSAGE, ERR_TX_IN_PROGRESS_MESSAGE, type EdgeDirection, type EdgePattern, EdgePatternBuilder, ErrBadConn, ErrClosed, ErrInvalidIdent, ErrInvalidString, ErrNoRows, ErrNoTx, ErrQueryInProgress, ErrRowsClosed, ErrTxDone, ErrTxInProgress, ExecuteRequest, ExecutionResponse, type ExplainOptions, type GQLEdge, type GQLId, type GQLNode, type GQLPath, type GQLRange, type GQLType, GQLValue, type GQLValueKind, GeodeCipher, GeodeClient, type GeodeConfig, type GeodeError, GrpcTransport, HelloRequest, HelloResponse, MAX_PAGE_SIZE, MAX_QUERY_LENGTH, MockTransport, type NodePattern, NodePatternBuilder, type OperationTiming, Param, type ParameterInfo, PatternBuilder, type PatternElement, type Permission, PingRequest, PingResponse, type PipelineExecutor, type PipelineTx, type PlanOperation, type PoolConfig, PredicateBuilder, type PredicateOp, PreparedStatement, type ProtoError, Row$1 as ProtoRow, type ProtoValue, PullRequest, PullResponse, QueryBuilder, type QueryOptions, type QueryParams, type QueryPlan, type QueryProfile, QueryResult, QueryResultIterator, QuicClientMessage, QuicServerMessage, QuicTransport, QuicTransport as QuicheTransport, type RLSPolicy, type RawEdge, type RetryPolicy, type Role, RollbackRequest, RollbackResponse, type Row, SUPPORTED_SCHEMES, SchemaDefinition, SecurityError, type SortDirection, StateError, type Statement, Status, StatusClass, type StatusClassType, Transaction, type Transport, TransportError, type TransportType, type User, batch, batchAll, batchExec, batchFirst, batchMap, batchParallel, buildBeginRequest, buildCommitRequest, buildExecuteRequest, buildHelloRequest, buildPingRequest, buildPullRequest, buildRollbackRequest, buildRollbackToRequest, buildSavepointRequest, buildTLSConfig, cloneConfig, createAuthClient, createCipher, createClient, createClientWithConfig, createTransport, decodeLengthPrefix, decodeQuicServerMessage, defaultConfig, defaultRetryPolicy, edge, encodeQuicClientMessage, encodeWithLengthPrefix, ensureProtoInitialized, explain, extractParameters, formatDSN, formatPlan, formatProfile, fromJSON, getAddress, getProtoPath, initProtoSync, isAuthError, isDriverError, isGeodeError, isRetryableError, isSentinelError, isSyntaxError, jsToProtoValue, node, parseDSN, parseGQLType, parseRow, parseSchemaFS, pattern, pipelineExec, predicate, prepare, profile, protoValueToJS, query, quoteIdent, quoteString, redactConfig, redactDSN, rowToObject, rowToRecord, sanitizeForLog, sanitizeGraphName, validateConfig, validateHostname, validatePageSize, validateParamName, validateParamValue, validatePort, validateQuery, validateSavepointName, withRetry, withTransaction };