@reifydb/client 0.4.1 → 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,33 +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);
1174
+ }
1175
+ if (response.type !== "Auth") {
1176
+ throw new Error(`Unexpected response type: ${response.type}`);
680
1177
  }
681
- if (Array.isArray(body)) {
682
- return [body];
1178
+ const payload = response.payload;
1179
+ if (payload.status !== "authenticated" || !payload.token || !payload.identity) {
1180
+ throw new Error("Authentication failed");
683
1181
  }
684
- if (body && typeof body === "object") {
685
- 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;
686
1188
  }
687
- 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();
688
1215
  }
689
1216
  handleDisconnect() {
690
1217
  this.rejectAllPendingRequests();
@@ -693,6 +1220,7 @@ var JsonWsClient = class _JsonWsClient {
693
1220
  }
694
1221
  const maxAttempts = this.options.maxReconnectAttempts ?? 5;
695
1222
  if (this.reconnectAttempts >= maxAttempts) {
1223
+ console.error(`Max reconnection attempts (${maxAttempts}) reached`);
696
1224
  return;
697
1225
  }
698
1226
  this.attemptReconnect();
@@ -702,6 +1230,7 @@ var JsonWsClient = class _JsonWsClient {
702
1230
  this.reconnectAttempts++;
703
1231
  const baseDelay = this.options.reconnectDelayMs ?? 1e3;
704
1232
  const delay = baseDelay * Math.pow(2, this.reconnectAttempts - 1);
1233
+ console.log(`Attempting reconnection in ${delay}ms`);
705
1234
  await new Promise((resolve) => setTimeout(resolve, delay));
706
1235
  try {
707
1236
  const socket = await createWebSocket2(this.options.url);
@@ -730,7 +1259,9 @@ var JsonWsClient = class _JsonWsClient {
730
1259
  socket.addEventListener("error", onError);
731
1260
  });
732
1261
  }
733
- 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
+ }
734
1265
  this.socket = socket;
735
1266
  this.setupSocketHandlers();
736
1267
  this.reconnectAttempts = 0;
@@ -746,15 +1277,16 @@ var JsonWsClient = class _JsonWsClient {
746
1277
  if (!msg.id) {
747
1278
  return;
748
1279
  }
749
- const { id } = msg;
1280
+ const { id, type, payload } = msg;
750
1281
  const handler = this.pending.get(id);
751
1282
  if (!handler) {
752
1283
  return;
753
1284
  }
754
1285
  this.pending.delete(id);
755
- handler(msg);
1286
+ handler({ id, type, payload });
756
1287
  };
757
- this.socket.onerror = () => {
1288
+ this.socket.onerror = (err) => {
1289
+ console.error("WebSocket error", err);
758
1290
  };
759
1291
  this.socket.onclose = () => {
760
1292
  this.handleDisconnect();
@@ -779,95 +1311,6 @@ var JsonWsClient = class _JsonWsClient {
779
1311
  }
780
1312
  };
781
1313
 
782
- // src/http.ts
783
- var JsonHttpClient = class _JsonHttpClient {
784
- constructor(options) {
785
- this.options = options;
786
- }
787
- static connect(options) {
788
- return new _JsonHttpClient(options);
789
- }
790
- async query(statements, params) {
791
- return this.send("query", statements, params);
792
- }
793
- async command(statements, params) {
794
- return this.send("command", statements, params);
795
- }
796
- async admin(statements, params) {
797
- return this.send("admin", statements, params);
798
- }
799
- async send(endpoint, statements, params) {
800
- const statementArray = Array.isArray(statements) ? statements : [statements];
801
- const outputStatements = statementArray.length > 1 ? statementArray.map((s) => s.trim() ? `OUTPUT ${s}` : s) : statementArray;
802
- const encodedParams = params !== void 0 && params !== null ? encodeParams(params) : void 0;
803
- const headers = {
804
- "Content-Type": "application/json"
805
- };
806
- if (this.options.token) {
807
- headers["Authorization"] = `Bearer ${this.options.token}`;
808
- } else if (this.options.apiKey) {
809
- headers["X-Api-Key"] = this.options.apiKey;
810
- }
811
- const baseUrl = this.options.url.replace(/\/+$/, "");
812
- const timeoutMs = this.options.timeoutMs ?? 3e4;
813
- const controller = new AbortController();
814
- const timeout = setTimeout(() => controller.abort(), timeoutMs);
815
- let response;
816
- try {
817
- response = await fetch(`${baseUrl}/v1/${endpoint}?format=json`, {
818
- method: "POST",
819
- headers,
820
- body: JSON.stringify({
821
- statements: outputStatements,
822
- params: encodedParams
823
- }),
824
- signal: controller.signal
825
- });
826
- } catch (err) {
827
- if (err.name === "AbortError") {
828
- throw new Error("ReifyDB query timeout");
829
- }
830
- throw err;
831
- } finally {
832
- clearTimeout(timeout);
833
- }
834
- const body = await response.json();
835
- if (!response.ok) {
836
- if (body.diagnostic) {
837
- throw new ReifyError({
838
- id: "",
839
- type: "Err",
840
- payload: { diagnostic: body.diagnostic }
841
- });
842
- }
843
- if (body.error) {
844
- throw new ReifyError({
845
- id: "",
846
- type: "Err",
847
- payload: {
848
- diagnostic: {
849
- code: body.code ?? "HTTP_ERROR",
850
- message: body.error,
851
- notes: []
852
- }
853
- }
854
- });
855
- }
856
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
857
- }
858
- if (Array.isArray(body) && body.length > 0 && Array.isArray(body[0])) {
859
- return body;
860
- }
861
- if (Array.isArray(body)) {
862
- return [body];
863
- }
864
- if (body && typeof body === "object") {
865
- return [[body]];
866
- }
867
- return [];
868
- }
869
- };
870
-
871
1314
  // src/index.ts
872
1315
  import { ReifyError as ReifyError2, asFrameResults } from "@reifydb/core";
873
1316
  var Client = class {
@@ -881,28 +1324,38 @@ var Client = class {
881
1324
  return WsClient.connect({ url, ...options });
882
1325
  }
883
1326
  /**
884
- * Connect to ReifyDB via WebSocket with JSON format responses
885
- * @param url WebSocket URL
1327
+ * Connect to ReifyDB via HTTP
1328
+ * @param url HTTP URL
886
1329
  * @param options Optional configuration
887
- * @returns Connected JSON WebSocket client
1330
+ * @returns HTTP client (sync, no connection to await)
888
1331
  */
889
- static async connect_json_ws(url, options = {}) {
890
- return JsonWsClient.connect({ url, ...options });
1332
+ static connect_http(url, options = {}) {
1333
+ return HttpClient.connect({ url, ...options });
891
1334
  }
892
1335
  /**
893
- * Connect to ReifyDB via HTTP with JSON format responses
894
- * @param url Base HTTP URL
1336
+ * Connect to ReifyDB via HTTP with JSON response format
1337
+ * @param url HTTP URL
895
1338
  * @param options Optional configuration
896
- * @returns JSON HTTP client
1339
+ * @returns JSON HTTP client (sync, no connection to await)
897
1340
  */
898
1341
  static connect_json_http(url, options = {}) {
899
1342
  return JsonHttpClient.connect({ url, ...options });
900
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
+ }
901
1353
  };
902
1354
  export {
903
1355
  Client,
1356
+ HttpClient,
904
1357
  JsonHttpClient,
905
- JsonWsClient,
1358
+ JsonWebsocketClient,
906
1359
  ReifyError2 as ReifyError,
907
1360
  WsClient,
908
1361
  asFrameResults