@reifydb/client 0.4.2 → 0.4.6

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.js CHANGED
@@ -143,7 +143,9 @@ var WsClient = class _WsClient {
143
143
  socket.addEventListener("error", onError);
144
144
  });
145
145
  }
146
- socket.send('{"id":"auth-1","type":"Auth","payload":{"token":"mysecrettoken"}}');
146
+ if (options.token) {
147
+ socket.send(JSON.stringify({ id: "auth-1", type: "Auth", payload: { token: options.token } }));
148
+ }
147
149
  return new _WsClient(socket, options);
148
150
  }
149
151
  /**
@@ -384,6 +386,71 @@ var WsClient = class _WsClient {
384
386
  }
385
387
  return value;
386
388
  }
389
+ async loginWithPassword(principal, password) {
390
+ return this.login("password", principal, { password });
391
+ }
392
+ async loginWithToken(principal, token) {
393
+ return this.login("token", principal, { token });
394
+ }
395
+ async login(method, principal, credentials) {
396
+ const id = `auth-${this.nextId++}`;
397
+ const request = {
398
+ id,
399
+ type: "Auth",
400
+ payload: { method, principal, credentials }
401
+ };
402
+ const response = await new Promise((resolve, reject) => {
403
+ const timeoutMs = this.options.timeoutMs ?? 3e4;
404
+ const timeout = setTimeout(() => {
405
+ this.pending.delete(id);
406
+ reject(new Error("Login timeout"));
407
+ }, timeoutMs);
408
+ this.pending.set(id, (res) => {
409
+ clearTimeout(timeout);
410
+ resolve(res);
411
+ });
412
+ this.socket.send(JSON.stringify(request));
413
+ });
414
+ if (response.type === "Err") {
415
+ throw new ReifyError(response);
416
+ }
417
+ if (response.type !== "Auth") {
418
+ throw new Error(`Unexpected response type: ${response.type}`);
419
+ }
420
+ const payload = response.payload;
421
+ if (payload.status !== "authenticated" || !payload.token || !payload.identity) {
422
+ throw new Error("Authentication failed");
423
+ }
424
+ this.options.token = payload.token;
425
+ return { token: payload.token, identity: payload.identity };
426
+ }
427
+ async logout() {
428
+ if (!this.options.token) {
429
+ return;
430
+ }
431
+ const id = `logout-${this.nextId++}`;
432
+ const request = {
433
+ id,
434
+ type: "Logout",
435
+ payload: {}
436
+ };
437
+ const response = await new Promise((resolve, reject) => {
438
+ const timeoutMs = this.options.timeoutMs ?? 3e4;
439
+ const timeout = setTimeout(() => {
440
+ this.pending.delete(id);
441
+ reject(new Error("Logout timeout"));
442
+ }, timeoutMs);
443
+ this.pending.set(id, (res) => {
444
+ clearTimeout(timeout);
445
+ resolve(res);
446
+ });
447
+ this.socket.send(JSON.stringify(request));
448
+ });
449
+ if (response.type === "Err") {
450
+ throw new ReifyError(response);
451
+ }
452
+ this.options = { ...this.options, token: void 0 };
453
+ }
387
454
  disconnect() {
388
455
  this.shouldReconnect = false;
389
456
  this.subscriptions.clear();
@@ -435,7 +502,9 @@ var WsClient = class _WsClient {
435
502
  socket.addEventListener("error", onError);
436
503
  });
437
504
  }
438
- socket.send('{"id":"auth-1","type":"Auth","payload":{"token":"mysecrettoken"}}');
505
+ if (this.options.token) {
506
+ socket.send(JSON.stringify({ id: "auth-1", type: "Auth", payload: { token: this.options.token } }));
507
+ }
439
508
  this.socket = socket;
440
509
  this.setupSocketHandlers();
441
510
  this.reconnectAttempts = 0;
@@ -468,14 +537,14 @@ var WsClient = class _WsClient {
468
537
  if (frames.length === 0) return;
469
538
  const frame = frames[0];
470
539
  const opColumn = frame.columns.find((c) => c.name === "_op");
471
- if (!opColumn || opColumn.data.length === 0) {
540
+ if (!opColumn || opColumn.payload.length === 0) {
472
541
  console.error("Missing or empty _op column:", { opColumn, frame });
473
542
  return;
474
543
  }
475
544
  const rows = this.frameToRows(frame, state.schema);
476
545
  const batches = [];
477
546
  for (let i = 0; i < rows.length; i++) {
478
- const opValue = parseInt(opColumn.data[i]);
547
+ const opValue = parseInt(opColumn.payload[i]);
479
548
  const operation = opValue === 1 ? "INSERT" : opValue === 2 ? "UPDATE" : opValue === 3 ? "REMOVE" : "INSERT";
480
549
  const { _op, ...cleanRow } = rows[i];
481
550
  if (batches.length > 0 && batches[batches.length - 1].op === operation) {
@@ -500,12 +569,12 @@ var WsClient = class _WsClient {
500
569
  }
501
570
  frameToRows(frame, schema) {
502
571
  if (!frame.columns || frame.columns.length === 0) return [];
503
- const rowCount = frame.columns[0].data.length;
572
+ const rowCount = frame.columns[0].payload.length;
504
573
  const rows = [];
505
574
  for (let i = 0; i < rowCount; i++) {
506
575
  const row = {};
507
576
  for (const col of frame.columns) {
508
- row[col.name] = decode({ type: col.type, value: col.data[i] });
577
+ row[col.name] = decode({ type: col.type, value: col.payload[i] });
509
578
  }
510
579
  rows.push(row);
511
580
  }
@@ -557,17 +626,390 @@ var WsClient = class _WsClient {
557
626
  }
558
627
  };
559
628
  function columnsToRows(columns) {
560
- const rowCount = columns[0]?.data.length ?? 0;
629
+ const rowCount = columns[0]?.payload.length ?? 0;
561
630
  return Array.from({ length: rowCount }, (_, i) => {
562
631
  const row = {};
563
632
  for (const col of columns) {
564
- row[col.name] = decode({ type: col.type, value: col.data[i] });
633
+ row[col.name] = decode({ type: col.type, value: col.payload[i] });
565
634
  }
566
635
  return row;
567
636
  });
568
637
  }
569
638
 
570
- // src/json.ts
639
+ // src/http.ts
640
+ import {
641
+ decode as decode2
642
+ } from "@reifydb/core";
643
+ var HttpClient = class _HttpClient {
644
+ constructor(options) {
645
+ this.options = options;
646
+ }
647
+ static connect(options) {
648
+ return new _HttpClient(options);
649
+ }
650
+ async loginWithPassword(principal, password) {
651
+ return this.login("password", principal, { password });
652
+ }
653
+ async loginWithToken(principal, token) {
654
+ return this.login("token", principal, { token });
655
+ }
656
+ async login(method, principal, credentials) {
657
+ const timeoutMs = this.options.timeoutMs ?? 3e4;
658
+ const controller = new AbortController();
659
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
660
+ try {
661
+ const response = await fetch(`${this.options.url}/v1/authenticate`, {
662
+ method: "POST",
663
+ headers: { "Content-Type": "application/json" },
664
+ body: JSON.stringify({ method, principal, credentials }),
665
+ signal: controller.signal
666
+ });
667
+ clearTimeout(timeout);
668
+ const body = await response.json();
669
+ if (body.status !== "authenticated" || !body.token || !body.identity) {
670
+ throw new Error(body.reason || "Authentication failed");
671
+ }
672
+ this.options = { ...this.options, token: body.token };
673
+ return { token: body.token, identity: body.identity };
674
+ } catch (err) {
675
+ clearTimeout(timeout);
676
+ if (err.name === "AbortError") throw new Error("Login timeout");
677
+ throw err;
678
+ }
679
+ }
680
+ async logout() {
681
+ if (!this.options.token) {
682
+ return;
683
+ }
684
+ const timeoutMs = this.options.timeoutMs ?? 3e4;
685
+ const controller = new AbortController();
686
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
687
+ try {
688
+ const response = await fetch(`${this.options.url}/v1/logout`, {
689
+ method: "POST",
690
+ headers: {
691
+ "Authorization": `Bearer ${this.options.token}`
692
+ },
693
+ signal: controller.signal
694
+ });
695
+ clearTimeout(timeout);
696
+ if (!response.ok) {
697
+ const body = await response.text();
698
+ throw new Error(`Logout failed: HTTP ${response.status}: ${body}`);
699
+ }
700
+ this.options = { ...this.options, token: void 0 };
701
+ } catch (err) {
702
+ clearTimeout(timeout);
703
+ if (err.name === "AbortError") throw new Error("Logout timeout");
704
+ throw err;
705
+ }
706
+ }
707
+ async admin(statements, params, schemas) {
708
+ const statementArray = Array.isArray(statements) ? statements : [statements];
709
+ const outputStatements = statementArray.length > 1 ? statementArray.map((s) => s.trim() ? `OUTPUT ${s}` : s) : statementArray;
710
+ const encodedParams = params !== void 0 && params !== null ? encodeParams(params) : void 0;
711
+ const result = await this.send("admin", outputStatements, encodedParams);
712
+ const transformedFrames = result.map((frame, frameIndex) => {
713
+ const frameSchema = schemas[frameIndex];
714
+ if (!frameSchema) {
715
+ return frame;
716
+ }
717
+ return frame.map((row) => this.transformResult(row, frameSchema));
718
+ });
719
+ return transformedFrames;
720
+ }
721
+ async command(statements, params, schemas) {
722
+ const statementArray = Array.isArray(statements) ? statements : [statements];
723
+ const outputStatements = statementArray.length > 1 ? statementArray.map((s) => s.trim() ? `OUTPUT ${s}` : s) : statementArray;
724
+ const encodedParams = params !== void 0 && params !== null ? encodeParams(params) : void 0;
725
+ const result = await this.send("command", outputStatements, encodedParams);
726
+ const transformedFrames = result.map((frame, frameIndex) => {
727
+ const frameSchema = schemas[frameIndex];
728
+ if (!frameSchema) {
729
+ return frame;
730
+ }
731
+ return frame.map((row) => this.transformResult(row, frameSchema));
732
+ });
733
+ return transformedFrames;
734
+ }
735
+ async query(statements, params, schemas) {
736
+ const statementArray = Array.isArray(statements) ? statements : [statements];
737
+ const outputStatements = statementArray.length > 1 ? statementArray.map((s) => s.trim() ? `OUTPUT ${s}` : s) : statementArray;
738
+ const encodedParams = params !== void 0 && params !== null ? encodeParams(params) : void 0;
739
+ const result = await this.send("query", outputStatements, encodedParams);
740
+ const transformedFrames = result.map((frame, frameIndex) => {
741
+ const frameSchema = schemas[frameIndex];
742
+ if (!frameSchema) {
743
+ return frame;
744
+ }
745
+ return frame.map((row) => this.transformResult(row, frameSchema));
746
+ });
747
+ return transformedFrames;
748
+ }
749
+ async send(endpoint, statements, params) {
750
+ const timeoutMs = this.options.timeoutMs ?? 3e4;
751
+ const controller = new AbortController();
752
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
753
+ const headers = {
754
+ "Content-Type": "application/json"
755
+ };
756
+ if (this.options.token) {
757
+ headers["Authorization"] = `Bearer ${this.options.token}`;
758
+ }
759
+ const body = { statements };
760
+ if (params !== void 0) {
761
+ body.params = params;
762
+ }
763
+ try {
764
+ const response = await fetch(`${this.options.url}/v1/${endpoint}`, {
765
+ method: "POST",
766
+ headers,
767
+ body: JSON.stringify(body),
768
+ signal: controller.signal,
769
+ credentials: "include"
770
+ });
771
+ clearTimeout(timeout);
772
+ const responseBody = await response.text();
773
+ let parsed;
774
+ try {
775
+ parsed = JSON.parse(responseBody);
776
+ } catch {
777
+ throw new Error(`Invalid JSON response: ${responseBody}`);
778
+ }
779
+ if (!response.ok) {
780
+ if (parsed.diagnostic) {
781
+ throw new ReifyError({
782
+ id: "",
783
+ type: "Err",
784
+ payload: { diagnostic: parsed.diagnostic }
785
+ });
786
+ }
787
+ throw new Error(parsed.error || `HTTP ${response.status}: ${responseBody}`);
788
+ }
789
+ const frames = parsed.frames || [];
790
+ return frames.map(
791
+ (frame) => columnsToRows2(frame.columns)
792
+ );
793
+ } catch (err) {
794
+ clearTimeout(timeout);
795
+ if (err.name === "AbortError") {
796
+ throw new Error("ReifyDB query timeout");
797
+ }
798
+ throw err;
799
+ }
800
+ }
801
+ transformResult(row, resultSchema) {
802
+ if (resultSchema && resultSchema.kind === "object" && resultSchema.properties) {
803
+ const transformedRow = {};
804
+ for (const [key, value] of Object.entries(row)) {
805
+ const propertySchema = resultSchema.properties[key];
806
+ if (propertySchema && propertySchema.kind === "primitive") {
807
+ if (value && typeof value === "object" && typeof value.valueOf === "function") {
808
+ const rawValue = value.valueOf();
809
+ transformedRow[key] = this.coerceToPrimitiveType(rawValue, propertySchema.type);
810
+ } else {
811
+ transformedRow[key] = this.coerceToPrimitiveType(value, propertySchema.type);
812
+ }
813
+ } else if (propertySchema && propertySchema.kind === "value") {
814
+ transformedRow[key] = value;
815
+ } else {
816
+ transformedRow[key] = propertySchema ? this.transformResult(value, propertySchema) : value;
817
+ }
818
+ }
819
+ return transformedRow;
820
+ }
821
+ if (resultSchema && resultSchema.kind === "primitive") {
822
+ if (row && typeof row === "object" && typeof row.valueOf === "function") {
823
+ return this.coerceToPrimitiveType(row.valueOf(), resultSchema.type);
824
+ }
825
+ return this.coerceToPrimitiveType(row, resultSchema.type);
826
+ }
827
+ if (resultSchema && resultSchema.kind === "value") {
828
+ return row;
829
+ }
830
+ if (resultSchema && resultSchema.kind === "array") {
831
+ if (Array.isArray(row)) {
832
+ return row.map((item) => this.transformResult(item, resultSchema.items));
833
+ }
834
+ return row;
835
+ }
836
+ if (resultSchema && resultSchema.kind === "optional") {
837
+ if (row === void 0 || row === null) {
838
+ return void 0;
839
+ }
840
+ return this.transformResult(row, resultSchema.schema);
841
+ }
842
+ return row;
843
+ }
844
+ coerceToPrimitiveType(value, schemaType) {
845
+ if (value === void 0 || value === null) {
846
+ return value;
847
+ }
848
+ const bigintTypes = ["Int8", "Int16", "Uint8", "Uint16"];
849
+ if (bigintTypes.includes(schemaType)) {
850
+ if (typeof value === "bigint") {
851
+ return value;
852
+ }
853
+ if (typeof value === "number") {
854
+ return BigInt(Math.trunc(value));
855
+ }
856
+ if (typeof value === "string") {
857
+ return BigInt(value);
858
+ }
859
+ }
860
+ return value;
861
+ }
862
+ };
863
+ function columnsToRows2(columns) {
864
+ const rowCount = columns[0]?.payload.length ?? 0;
865
+ return Array.from({ length: rowCount }, (_, i) => {
866
+ const row = {};
867
+ for (const col of columns) {
868
+ row[col.name] = decode2({ type: col.type, value: col.payload[i] });
869
+ }
870
+ return row;
871
+ });
872
+ }
873
+
874
+ // src/json-http.ts
875
+ var JsonHttpClient = class _JsonHttpClient {
876
+ constructor(options) {
877
+ this.options = options;
878
+ }
879
+ static connect(options) {
880
+ return new _JsonHttpClient(options);
881
+ }
882
+ async loginWithPassword(principal, password) {
883
+ return this.login("password", principal, { password });
884
+ }
885
+ async loginWithToken(principal, token) {
886
+ return this.login("token", principal, { token });
887
+ }
888
+ async login(method, principal, credentials) {
889
+ const timeoutMs = this.options.timeoutMs ?? 3e4;
890
+ const controller = new AbortController();
891
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
892
+ try {
893
+ const response = await fetch(`${this.options.url}/v1/authenticate`, {
894
+ method: "POST",
895
+ headers: { "Content-Type": "application/json" },
896
+ body: JSON.stringify({ method, principal, credentials }),
897
+ signal: controller.signal
898
+ });
899
+ clearTimeout(timeout);
900
+ const body = await response.json();
901
+ if (body.status !== "authenticated" || !body.token || !body.identity) {
902
+ throw new Error(body.reason || "Authentication failed");
903
+ }
904
+ this.options = { ...this.options, token: body.token };
905
+ return { token: body.token, identity: body.identity };
906
+ } catch (err) {
907
+ clearTimeout(timeout);
908
+ if (err.name === "AbortError") throw new Error("Login timeout");
909
+ throw err;
910
+ }
911
+ }
912
+ async logout() {
913
+ if (!this.options.token) {
914
+ return;
915
+ }
916
+ const timeoutMs = this.options.timeoutMs ?? 3e4;
917
+ const controller = new AbortController();
918
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
919
+ try {
920
+ const response = await fetch(`${this.options.url}/v1/logout`, {
921
+ method: "POST",
922
+ headers: {
923
+ "Authorization": `Bearer ${this.options.token}`
924
+ },
925
+ signal: controller.signal
926
+ });
927
+ clearTimeout(timeout);
928
+ if (!response.ok) {
929
+ const body = await response.text();
930
+ throw new Error(`Logout failed: HTTP ${response.status}: ${body}`);
931
+ }
932
+ this.options = { ...this.options, token: void 0 };
933
+ } catch (err) {
934
+ clearTimeout(timeout);
935
+ if (err.name === "AbortError") throw new Error("Logout timeout");
936
+ throw err;
937
+ }
938
+ }
939
+ async admin(statements, params) {
940
+ const statementArray = Array.isArray(statements) ? statements : [statements];
941
+ const outputStatements = statementArray.length > 1 ? statementArray.map((s) => s.trim() ? `OUTPUT ${s}` : s) : statementArray;
942
+ const encodedParams = params !== void 0 && params !== null ? encodeParams(params) : void 0;
943
+ return this.send("admin", outputStatements, encodedParams);
944
+ }
945
+ async command(statements, params) {
946
+ const statementArray = Array.isArray(statements) ? statements : [statements];
947
+ const outputStatements = statementArray.length > 1 ? statementArray.map((s) => s.trim() ? `OUTPUT ${s}` : s) : statementArray;
948
+ const encodedParams = params !== void 0 && params !== null ? encodeParams(params) : void 0;
949
+ return this.send("command", outputStatements, encodedParams);
950
+ }
951
+ async query(statements, params) {
952
+ const statementArray = Array.isArray(statements) ? statements : [statements];
953
+ const outputStatements = statementArray.length > 1 ? statementArray.map((s) => s.trim() ? `OUTPUT ${s}` : s) : statementArray;
954
+ const encodedParams = params !== void 0 && params !== null ? encodeParams(params) : void 0;
955
+ return this.send("query", outputStatements, encodedParams);
956
+ }
957
+ async send(endpoint, statements, params) {
958
+ const timeoutMs = this.options.timeoutMs ?? 3e4;
959
+ const controller = new AbortController();
960
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
961
+ const headers = {
962
+ "Content-Type": "application/json"
963
+ };
964
+ if (this.options.token) {
965
+ headers["Authorization"] = `Bearer ${this.options.token}`;
966
+ }
967
+ const body = { statements };
968
+ if (params !== void 0) {
969
+ body.params = params;
970
+ }
971
+ const queryParams = new URLSearchParams({ format: "json" });
972
+ if (this.options.unwrap) {
973
+ queryParams.set("unwrap", "true");
974
+ }
975
+ try {
976
+ const response = await fetch(`${this.options.url}/v1/${endpoint}?${queryParams}`, {
977
+ method: "POST",
978
+ headers,
979
+ body: JSON.stringify(body),
980
+ signal: controller.signal,
981
+ credentials: "include"
982
+ });
983
+ clearTimeout(timeout);
984
+ const responseBody = await response.text();
985
+ let parsed;
986
+ try {
987
+ parsed = JSON.parse(responseBody);
988
+ } catch {
989
+ throw new Error(`Invalid JSON response: ${responseBody}`);
990
+ }
991
+ if (!response.ok) {
992
+ if (parsed.diagnostic) {
993
+ throw new ReifyError({
994
+ id: "",
995
+ type: "Err",
996
+ payload: { diagnostic: parsed.diagnostic }
997
+ });
998
+ }
999
+ throw new Error(parsed.error || `HTTP ${response.status}: ${responseBody}`);
1000
+ }
1001
+ return parsed;
1002
+ } catch (err) {
1003
+ clearTimeout(timeout);
1004
+ if (err.name === "AbortError") {
1005
+ throw new Error("ReifyDB query timeout");
1006
+ }
1007
+ throw err;
1008
+ }
1009
+ }
1010
+ };
1011
+
1012
+ // src/json-ws.ts
571
1013
  async function createWebSocket2(url) {
572
1014
  if (typeof window !== "undefined" && typeof window.WebSocket !== "undefined") {
573
1015
  return new WebSocket(url);
@@ -576,7 +1018,7 @@ async function createWebSocket2(url) {
576
1018
  return new wsModule.WebSocket(url);
577
1019
  }
578
1020
  }
579
- var JsonWsClient = class _JsonWsClient {
1021
+ var JsonWebsocketClient = class _JsonWebsocketClient {
580
1022
  constructor(socket, options) {
581
1023
  this.pending = /* @__PURE__ */ new Map();
582
1024
  this.reconnectAttempts = 0;
@@ -614,27 +1056,61 @@ var JsonWsClient = class _JsonWsClient {
614
1056
  socket.addEventListener("error", onError);
615
1057
  });
616
1058
  }
617
- socket.send('{"id":"auth-1","type":"Auth","payload":{"token":"mysecrettoken"}}');
618
- return new _JsonWsClient(socket, options);
619
- }
620
- async query(statements, params) {
621
- return this.send("Query", statements, params);
622
- }
623
- async command(statements, params) {
624
- return this.send("Command", statements, params);
1059
+ if (options.token) {
1060
+ socket.send(JSON.stringify({ id: "auth-1", type: "Auth", payload: { token: options.token } }));
1061
+ }
1062
+ return new _JsonWebsocketClient(socket, options);
625
1063
  }
626
1064
  async admin(statements, params) {
627
- return this.send("Admin", statements, params);
1065
+ const id = `req-${this.nextId++}`;
1066
+ const statementArray = Array.isArray(statements) ? statements : [statements];
1067
+ const outputStatements = statementArray.length > 1 ? statementArray.map((s) => s.trim() ? `OUTPUT ${s}` : s) : statementArray;
1068
+ const encodedParams = params !== void 0 && params !== null ? encodeParams(params) : void 0;
1069
+ return this.send({
1070
+ id,
1071
+ type: "Admin",
1072
+ payload: {
1073
+ statements: outputStatements,
1074
+ params: encodedParams,
1075
+ format: "json",
1076
+ ...this.options.unwrap ? { unwrap: true } : {}
1077
+ }
1078
+ });
628
1079
  }
629
- disconnect() {
630
- this.shouldReconnect = false;
631
- this.socket.close();
1080
+ async command(statements, params) {
1081
+ const id = `req-${this.nextId++}`;
1082
+ const statementArray = Array.isArray(statements) ? statements : [statements];
1083
+ const outputStatements = statementArray.length > 1 ? statementArray.map((s) => s.trim() ? `OUTPUT ${s}` : s) : statementArray;
1084
+ const encodedParams = params !== void 0 && params !== null ? encodeParams(params) : void 0;
1085
+ return this.send({
1086
+ id,
1087
+ type: "Command",
1088
+ payload: {
1089
+ statements: outputStatements,
1090
+ params: encodedParams,
1091
+ format: "json",
1092
+ ...this.options.unwrap ? { unwrap: true } : {}
1093
+ }
1094
+ });
632
1095
  }
633
- async send(type, statements, params) {
1096
+ async query(statements, params) {
634
1097
  const id = `req-${this.nextId++}`;
635
1098
  const statementArray = Array.isArray(statements) ? statements : [statements];
636
1099
  const outputStatements = statementArray.length > 1 ? statementArray.map((s) => s.trim() ? `OUTPUT ${s}` : s) : statementArray;
637
1100
  const encodedParams = params !== void 0 && params !== null ? encodeParams(params) : void 0;
1101
+ return this.send({
1102
+ id,
1103
+ type: "Query",
1104
+ payload: {
1105
+ statements: outputStatements,
1106
+ params: encodedParams,
1107
+ format: "json",
1108
+ ...this.options.unwrap ? { unwrap: true } : {}
1109
+ }
1110
+ });
1111
+ }
1112
+ async send(req) {
1113
+ const id = req.id;
638
1114
  if (this.socket.readyState !== 1) {
639
1115
  throw new ReifyError({
640
1116
  id: "connection-error",
@@ -658,36 +1134,84 @@ var JsonWsClient = class _JsonWsClient {
658
1134
  clearTimeout(timeout);
659
1135
  resolve(res);
660
1136
  });
661
- this.socket.send(JSON.stringify({
662
- id,
663
- type,
664
- payload: {
665
- statements: outputStatements,
666
- params: encodedParams,
667
- format: "json"
668
- }
669
- }));
1137
+ this.socket.send(JSON.stringify(req));
670
1138
  });
671
1139
  if (response.type === "Err") {
672
1140
  throw new ReifyError(response);
673
1141
  }
674
- if (response.type !== type) {
1142
+ if (response.type !== req.type) {
675
1143
  throw new Error(`Unexpected response type: ${response.type}`);
676
1144
  }
677
- const body = response.payload.body;
678
- if (Array.isArray(body) && body.length > 0 && Array.isArray(body[0])) {
679
- return body;
1145
+ return response.payload.body;
1146
+ }
1147
+ async loginWithPassword(principal, password) {
1148
+ return this.login("password", principal, { password });
1149
+ }
1150
+ async loginWithToken(principal, token) {
1151
+ return this.login("token", principal, { token });
1152
+ }
1153
+ async login(method, principal, credentials) {
1154
+ const id = `auth-${this.nextId++}`;
1155
+ const request = {
1156
+ id,
1157
+ type: "Auth",
1158
+ payload: { method, principal, credentials }
1159
+ };
1160
+ const response = await new Promise((resolve, reject) => {
1161
+ const timeoutMs = this.options.timeoutMs ?? 3e4;
1162
+ const timeout = setTimeout(() => {
1163
+ this.pending.delete(id);
1164
+ reject(new Error("Login timeout"));
1165
+ }, timeoutMs);
1166
+ this.pending.set(id, (res) => {
1167
+ clearTimeout(timeout);
1168
+ resolve(res);
1169
+ });
1170
+ this.socket.send(JSON.stringify(request));
1171
+ });
1172
+ if (response.type === "Err") {
1173
+ throw new ReifyError(response);
680
1174
  }
681
- if (Array.isArray(body) && body.length === 0) {
682
- return [];
1175
+ if (response.type !== "Auth") {
1176
+ throw new Error(`Unexpected response type: ${response.type}`);
683
1177
  }
684
- if (Array.isArray(body)) {
685
- return [body];
1178
+ const payload = response.payload;
1179
+ if (payload.status !== "authenticated" || !payload.token || !payload.identity) {
1180
+ throw new Error("Authentication failed");
686
1181
  }
687
- if (body && typeof body === "object") {
688
- return [[body]];
1182
+ this.options.token = payload.token;
1183
+ return { token: payload.token, identity: payload.identity };
1184
+ }
1185
+ async logout() {
1186
+ if (!this.options.token) {
1187
+ return;
689
1188
  }
690
- return [];
1189
+ const id = `logout-${this.nextId++}`;
1190
+ const request = {
1191
+ id,
1192
+ type: "Logout",
1193
+ payload: {}
1194
+ };
1195
+ const response = await new Promise((resolve, reject) => {
1196
+ const timeoutMs = this.options.timeoutMs ?? 3e4;
1197
+ const timeout = setTimeout(() => {
1198
+ this.pending.delete(id);
1199
+ reject(new Error("Logout timeout"));
1200
+ }, timeoutMs);
1201
+ this.pending.set(id, (res) => {
1202
+ clearTimeout(timeout);
1203
+ resolve(res);
1204
+ });
1205
+ this.socket.send(JSON.stringify(request));
1206
+ });
1207
+ if (response.type === "Err") {
1208
+ throw new ReifyError(response);
1209
+ }
1210
+ this.options = { ...this.options, token: void 0 };
1211
+ }
1212
+ disconnect() {
1213
+ this.shouldReconnect = false;
1214
+ this.socket.close();
691
1215
  }
692
1216
  handleDisconnect() {
693
1217
  this.rejectAllPendingRequests();
@@ -696,6 +1220,7 @@ var JsonWsClient = class _JsonWsClient {
696
1220
  }
697
1221
  const maxAttempts = this.options.maxReconnectAttempts ?? 5;
698
1222
  if (this.reconnectAttempts >= maxAttempts) {
1223
+ console.error(`Max reconnection attempts (${maxAttempts}) reached`);
699
1224
  return;
700
1225
  }
701
1226
  this.attemptReconnect();
@@ -705,6 +1230,7 @@ var JsonWsClient = class _JsonWsClient {
705
1230
  this.reconnectAttempts++;
706
1231
  const baseDelay = this.options.reconnectDelayMs ?? 1e3;
707
1232
  const delay = baseDelay * Math.pow(2, this.reconnectAttempts - 1);
1233
+ console.log(`Attempting reconnection in ${delay}ms`);
708
1234
  await new Promise((resolve) => setTimeout(resolve, delay));
709
1235
  try {
710
1236
  const socket = await createWebSocket2(this.options.url);
@@ -733,7 +1259,9 @@ var JsonWsClient = class _JsonWsClient {
733
1259
  socket.addEventListener("error", onError);
734
1260
  });
735
1261
  }
736
- socket.send('{"id":"auth-1","type":"Auth","payload":{"token":"mysecrettoken"}}');
1262
+ if (this.options.token) {
1263
+ socket.send(JSON.stringify({ id: "auth-1", type: "Auth", payload: { token: this.options.token } }));
1264
+ }
737
1265
  this.socket = socket;
738
1266
  this.setupSocketHandlers();
739
1267
  this.reconnectAttempts = 0;
@@ -749,15 +1277,16 @@ var JsonWsClient = class _JsonWsClient {
749
1277
  if (!msg.id) {
750
1278
  return;
751
1279
  }
752
- const { id } = msg;
1280
+ const { id, type, payload } = msg;
753
1281
  const handler = this.pending.get(id);
754
1282
  if (!handler) {
755
1283
  return;
756
1284
  }
757
1285
  this.pending.delete(id);
758
- handler(msg);
1286
+ handler({ id, type, payload });
759
1287
  };
760
- this.socket.onerror = () => {
1288
+ this.socket.onerror = (err) => {
1289
+ console.error("WebSocket error", err);
761
1290
  };
762
1291
  this.socket.onclose = () => {
763
1292
  this.handleDisconnect();
@@ -782,95 +1311,6 @@ var JsonWsClient = class _JsonWsClient {
782
1311
  }
783
1312
  };
784
1313
 
785
- // src/http.ts
786
- var JsonHttpClient = class _JsonHttpClient {
787
- constructor(options) {
788
- this.options = options;
789
- }
790
- static connect(options) {
791
- return new _JsonHttpClient(options);
792
- }
793
- async query(statements, params) {
794
- return this.send("query", statements, params);
795
- }
796
- async command(statements, params) {
797
- return this.send("command", statements, params);
798
- }
799
- async admin(statements, params) {
800
- return this.send("admin", statements, params);
801
- }
802
- async send(endpoint, statements, params) {
803
- const statementArray = Array.isArray(statements) ? statements : [statements];
804
- const outputStatements = statementArray.length > 1 ? statementArray.map((s) => s.trim() ? `OUTPUT ${s}` : s) : statementArray;
805
- const encodedParams = params !== void 0 && params !== null ? encodeParams(params) : void 0;
806
- const headers = {
807
- "Content-Type": "application/json"
808
- };
809
- if (this.options.token) {
810
- headers["Authorization"] = `Bearer ${this.options.token}`;
811
- } else if (this.options.apiKey) {
812
- headers["X-Api-Key"] = this.options.apiKey;
813
- }
814
- const baseUrl = this.options.url.replace(/\/+$/, "");
815
- const timeoutMs = this.options.timeoutMs ?? 3e4;
816
- const controller = new AbortController();
817
- const timeout = setTimeout(() => controller.abort(), timeoutMs);
818
- let response;
819
- try {
820
- response = await fetch(`${baseUrl}/v1/${endpoint}?format=json`, {
821
- method: "POST",
822
- headers,
823
- body: JSON.stringify({
824
- statements: outputStatements,
825
- params: encodedParams
826
- }),
827
- signal: controller.signal
828
- });
829
- } catch (err) {
830
- if (err.name === "AbortError") {
831
- throw new Error("ReifyDB query timeout");
832
- }
833
- throw err;
834
- } finally {
835
- clearTimeout(timeout);
836
- }
837
- const body = await response.json();
838
- if (!response.ok) {
839
- if (body.diagnostic) {
840
- throw new ReifyError({
841
- id: "",
842
- type: "Err",
843
- payload: { diagnostic: body.diagnostic }
844
- });
845
- }
846
- if (body.error) {
847
- throw new ReifyError({
848
- id: "",
849
- type: "Err",
850
- payload: {
851
- diagnostic: {
852
- code: body.code ?? "HTTP_ERROR",
853
- message: body.error,
854
- notes: []
855
- }
856
- }
857
- });
858
- }
859
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
860
- }
861
- if (Array.isArray(body) && body.length > 0 && Array.isArray(body[0])) {
862
- return body;
863
- }
864
- if (Array.isArray(body)) {
865
- return [body];
866
- }
867
- if (body && typeof body === "object") {
868
- return [[body]];
869
- }
870
- return [];
871
- }
872
- };
873
-
874
1314
  // src/index.ts
875
1315
  import { ReifyError as ReifyError2, asFrameResults } from "@reifydb/core";
876
1316
  var Client = class {
@@ -884,28 +1324,38 @@ var Client = class {
884
1324
  return WsClient.connect({ url, ...options });
885
1325
  }
886
1326
  /**
887
- * Connect to ReifyDB via WebSocket with JSON format responses
888
- * @param url WebSocket URL
1327
+ * Connect to ReifyDB via HTTP
1328
+ * @param url HTTP URL
889
1329
  * @param options Optional configuration
890
- * @returns Connected JSON WebSocket client
1330
+ * @returns HTTP client (sync, no connection to await)
891
1331
  */
892
- static async connect_json_ws(url, options = {}) {
893
- return JsonWsClient.connect({ url, ...options });
1332
+ static connect_http(url, options = {}) {
1333
+ return HttpClient.connect({ url, ...options });
894
1334
  }
895
1335
  /**
896
- * Connect to ReifyDB via HTTP with JSON format responses
897
- * @param url Base HTTP URL
1336
+ * Connect to ReifyDB via HTTP with JSON response format
1337
+ * @param url HTTP URL
898
1338
  * @param options Optional configuration
899
- * @returns JSON HTTP client
1339
+ * @returns JSON HTTP client (sync, no connection to await)
900
1340
  */
901
1341
  static connect_json_http(url, options = {}) {
902
1342
  return JsonHttpClient.connect({ url, ...options });
903
1343
  }
1344
+ /**
1345
+ * Connect to ReifyDB via WebSocket with JSON response format
1346
+ * @param url WebSocket URL
1347
+ * @param options Optional configuration
1348
+ * @returns Connected JSON WebSocket client
1349
+ */
1350
+ static async connect_json_ws(url, options = {}) {
1351
+ return JsonWebsocketClient.connect({ url, ...options });
1352
+ }
904
1353
  };
905
1354
  export {
906
1355
  Client,
1356
+ HttpClient,
907
1357
  JsonHttpClient,
908
- JsonWsClient,
1358
+ JsonWebsocketClient,
909
1359
  ReifyError2 as ReifyError,
910
1360
  WsClient,
911
1361
  asFrameResults