@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.d.ts +87 -30
- package/dist/index.js +596 -143
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -143,7 +143,9 @@ var WsClient = class _WsClient {
|
|
|
143
143
|
socket.addEventListener("error", onError);
|
|
144
144
|
});
|
|
145
145
|
}
|
|
146
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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].
|
|
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.
|
|
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]?.
|
|
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.
|
|
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/
|
|
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
|
|
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
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
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
|
-
|
|
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
|
-
|
|
630
|
-
|
|
631
|
-
|
|
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
|
|
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
|
-
|
|
678
|
-
|
|
679
|
-
|
|
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
|
-
|
|
682
|
-
|
|
1178
|
+
const payload = response.payload;
|
|
1179
|
+
if (payload.status !== "authenticated" || !payload.token || !payload.identity) {
|
|
1180
|
+
throw new Error("Authentication failed");
|
|
683
1181
|
}
|
|
684
|
-
|
|
685
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
885
|
-
* @param url
|
|
1327
|
+
* Connect to ReifyDB via HTTP
|
|
1328
|
+
* @param url HTTP URL
|
|
886
1329
|
* @param options Optional configuration
|
|
887
|
-
* @returns
|
|
1330
|
+
* @returns HTTP client (sync, no connection to await)
|
|
888
1331
|
*/
|
|
889
|
-
static
|
|
890
|
-
return
|
|
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
|
|
894
|
-
* @param 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
|
-
|
|
1358
|
+
JsonWebsocketClient,
|
|
906
1359
|
ReifyError2 as ReifyError,
|
|
907
1360
|
WsClient,
|
|
908
1361
|
asFrameResults
|