@rustrak/client 0.13.0 → 0.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +668 -16
- package/README.md +123 -37
- package/dist/index.cjs +850 -417
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +195 -144
- package/dist/index.d.ts +195 -144
- package/dist/index.js +841 -409
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -451,6 +451,11 @@ var chunkUploadCapabilitySchema = z.object({
|
|
|
451
451
|
accept: z.array(z.string()),
|
|
452
452
|
concurrency: z.number().int().optional()
|
|
453
453
|
});
|
|
454
|
+
var assembleInputSchema = z.object({
|
|
455
|
+
checksum: z.string().min(1),
|
|
456
|
+
chunks: z.array(z.string().min(1)),
|
|
457
|
+
projects: z.array(z.string().min(1)).min(1)
|
|
458
|
+
});
|
|
454
459
|
var assembleResponseSchema = z.object({
|
|
455
460
|
state: z.string(),
|
|
456
461
|
missingChunks: z.array(z.string()),
|
|
@@ -633,117 +638,330 @@ var registerRequestSchema = z.object({
|
|
|
633
638
|
password: z.string().min(1)
|
|
634
639
|
});
|
|
635
640
|
|
|
636
|
-
// src/errors
|
|
637
|
-
var
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
super(message);
|
|
652
|
-
this.name = this.constructor.name;
|
|
653
|
-
this.retryable = options?.retryable ?? false;
|
|
654
|
-
this.statusCode = options?.statusCode;
|
|
655
|
-
this.cause = options?.cause;
|
|
656
|
-
if (Error.captureStackTrace) {
|
|
657
|
-
Error.captureStackTrace(this, this.constructor);
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
};
|
|
641
|
+
// src/errors.ts
|
|
642
|
+
var FIELD_ERROR_CODES = [
|
|
643
|
+
"required",
|
|
644
|
+
"invalid",
|
|
645
|
+
"already_exists",
|
|
646
|
+
"too_short",
|
|
647
|
+
"too_long",
|
|
648
|
+
"custom"
|
|
649
|
+
];
|
|
650
|
+
var SERVER_ERROR_MESSAGE = "The server failed to handle the request.";
|
|
651
|
+
var NETWORK_ERROR_MESSAGE = "The request could not reach the server.";
|
|
652
|
+
var TIMEOUT_ERROR_MESSAGE = "The request timed out.";
|
|
653
|
+
function isRetryable(error) {
|
|
654
|
+
return error.kind === "network" || error.kind === "server_error" || error.kind === "rate_limited";
|
|
655
|
+
}
|
|
661
656
|
|
|
662
|
-
// src/
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
657
|
+
// src/result.ts
|
|
658
|
+
function Ok(data) {
|
|
659
|
+
return { success: true, data };
|
|
660
|
+
}
|
|
661
|
+
function Err(error) {
|
|
662
|
+
return { success: false, error };
|
|
663
|
+
}
|
|
664
|
+
function unwrap(result) {
|
|
665
|
+
if (result.success) {
|
|
666
|
+
return result.data;
|
|
666
667
|
}
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
668
|
+
throw new Error(
|
|
669
|
+
`unwrap() called on a failed Result: ${describe(result.error)}`
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
function unwrapOr(result, fallback) {
|
|
673
|
+
return result.success ? result.data : fallback;
|
|
674
|
+
}
|
|
675
|
+
function mapResult(result, fn) {
|
|
676
|
+
return result.success ? Ok(fn(result.data)) : result;
|
|
677
|
+
}
|
|
678
|
+
function describe(error) {
|
|
679
|
+
if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
|
|
680
|
+
return error.message;
|
|
671
681
|
}
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
682
|
+
return String(error);
|
|
683
|
+
}
|
|
684
|
+
var RustrakTransportFailure = class extends Error {
|
|
685
|
+
rustrakError;
|
|
686
|
+
constructor(error) {
|
|
687
|
+
super(error.message);
|
|
688
|
+
this.name = "RustrakTransportFailure";
|
|
689
|
+
this.rustrakError = error;
|
|
676
690
|
}
|
|
677
691
|
};
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
692
|
+
function isTransportFailure(value) {
|
|
693
|
+
return value instanceof RustrakTransportFailure;
|
|
694
|
+
}
|
|
695
|
+
function readErrorMessage(error, status) {
|
|
696
|
+
const fallback = `HTTP ${status} error`;
|
|
697
|
+
const body = error.data;
|
|
698
|
+
if (body && typeof body === "object") {
|
|
699
|
+
const nested = typeof body.error === "object" ? body.error?.message : body.error;
|
|
700
|
+
return nested || body.message || fallback;
|
|
684
701
|
}
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
702
|
+
return fallback;
|
|
703
|
+
}
|
|
704
|
+
var KNOWN_FIELD_ERROR_CODES = new Set(FIELD_ERROR_CODES);
|
|
705
|
+
function isFieldErrorCode(value) {
|
|
706
|
+
return typeof value === "string" && KNOWN_FIELD_ERROR_CODES.has(value);
|
|
707
|
+
}
|
|
708
|
+
var warnedFieldErrorCodes = /* @__PURE__ */ new Set();
|
|
709
|
+
function warnUnknownFieldErrorCode(code, field) {
|
|
710
|
+
if (warnedFieldErrorCodes.has(code)) return;
|
|
711
|
+
warnedFieldErrorCodes.add(code);
|
|
712
|
+
console.warn(
|
|
713
|
+
`[@rustrak/client] Dropped a field error with an unrecognised code "${code}" (field "${field}"). This client build does not know that code, so the affected inputs degrade to a form-level error. The server is most likely newer than @rustrak/client; upgrade the client to match the server version.`
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
function readFieldErrors(error) {
|
|
717
|
+
const body = error.data;
|
|
718
|
+
const raw = body && typeof body === "object" ? body.error?.fields : void 0;
|
|
719
|
+
if (!Array.isArray(raw)) {
|
|
720
|
+
return void 0;
|
|
721
|
+
}
|
|
722
|
+
const fields = [];
|
|
723
|
+
for (const entry of raw) {
|
|
724
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
725
|
+
const { field, code, message } = entry;
|
|
726
|
+
if (typeof field !== "string") continue;
|
|
727
|
+
if (!isFieldErrorCode(code)) {
|
|
728
|
+
if (typeof code === "string") warnUnknownFieldErrorCode(code, field);
|
|
729
|
+
continue;
|
|
695
730
|
}
|
|
731
|
+
fields.push(
|
|
732
|
+
code === "custom" && typeof message === "string" ? { field, code, message } : { field, code }
|
|
733
|
+
);
|
|
696
734
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
735
|
+
return fields.length > 0 ? fields : void 0;
|
|
736
|
+
}
|
|
737
|
+
function readRetryAfter(response) {
|
|
738
|
+
const header = response.headers.get("Retry-After")?.trim();
|
|
739
|
+
if (!header) {
|
|
740
|
+
return void 0;
|
|
701
741
|
}
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
constructor(message) {
|
|
705
|
-
super(message, { retryable: false, statusCode: 400 });
|
|
742
|
+
if (/^\d+$/.test(header)) {
|
|
743
|
+
return Number.parseInt(header, 10);
|
|
706
744
|
}
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
// src/errors/validation.ts
|
|
710
|
-
var ValidationError = class extends RustrakError {
|
|
711
|
-
/**
|
|
712
|
-
* Zod validation errors
|
|
713
|
-
*/
|
|
714
|
-
validationErrors;
|
|
715
|
-
constructor(message, validationErrors) {
|
|
716
|
-
super(message, { retryable: false });
|
|
717
|
-
this.validationErrors = validationErrors;
|
|
745
|
+
if (/^[+-]\d+$/.test(header)) {
|
|
746
|
+
return void 0;
|
|
718
747
|
}
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
748
|
+
const date = Date.parse(header);
|
|
749
|
+
if (Number.isNaN(date)) {
|
|
750
|
+
return void 0;
|
|
751
|
+
}
|
|
752
|
+
return Math.max(0, Math.ceil((date - Date.now()) / 1e3));
|
|
753
|
+
}
|
|
754
|
+
function annotate(base, fields) {
|
|
755
|
+
return fields === void 0 ? base : { ...base, fields };
|
|
756
|
+
}
|
|
757
|
+
function transformHttpError(error) {
|
|
758
|
+
const { response } = error;
|
|
759
|
+
const status = response.status;
|
|
760
|
+
if (status >= 500) {
|
|
761
|
+
return { kind: "server_error", status, message: SERVER_ERROR_MESSAGE };
|
|
762
|
+
}
|
|
763
|
+
const message = readErrorMessage(error, status);
|
|
764
|
+
const fields = readFieldErrors(error);
|
|
765
|
+
switch (status) {
|
|
766
|
+
case 400:
|
|
767
|
+
return annotate({ kind: "validation", status, message }, fields);
|
|
768
|
+
case 401:
|
|
769
|
+
return annotate({ kind: "unauthenticated", status, message }, fields);
|
|
770
|
+
case 403:
|
|
771
|
+
return annotate({ kind: "forbidden", status, message }, fields);
|
|
772
|
+
case 404:
|
|
773
|
+
return annotate({ kind: "not_found", status, message }, fields);
|
|
774
|
+
case 409:
|
|
775
|
+
return annotate({ kind: "conflict", status, message }, fields);
|
|
776
|
+
case 410:
|
|
777
|
+
return annotate({ kind: "gone", status, message }, fields);
|
|
778
|
+
case 413:
|
|
779
|
+
return annotate({ kind: "payload_too_large", status, message }, fields);
|
|
780
|
+
case 429: {
|
|
781
|
+
const retryAfter = readRetryAfter(response);
|
|
782
|
+
return annotate(
|
|
783
|
+
retryAfter === void 0 ? { kind: "rate_limited", status, message } : { kind: "rate_limited", status, message, retryAfter },
|
|
784
|
+
fields
|
|
785
|
+
);
|
|
725
786
|
}
|
|
726
|
-
|
|
727
|
-
|
|
787
|
+
default:
|
|
788
|
+
return annotate({ kind: "client_error", status, message }, fields);
|
|
728
789
|
}
|
|
729
|
-
}
|
|
790
|
+
}
|
|
791
|
+
function createKyInstance(config) {
|
|
792
|
+
const headers = {
|
|
793
|
+
// `Accept` is set here rather than relied on from ky. The `.json()`
|
|
794
|
+
// shortcut sets it before the request is issued, and `BaseResource` no
|
|
795
|
+
// longer uses that shortcut: it awaits the `Response` and parses the body
|
|
796
|
+
// itself, so without this every one of the 86 methods would send `*/*` and
|
|
797
|
+
// any content-negotiating hop could answer with HTML.
|
|
798
|
+
Accept: "application/json",
|
|
799
|
+
"Content-Type": "application/json",
|
|
800
|
+
...config.headers
|
|
801
|
+
};
|
|
802
|
+
if (config.token) {
|
|
803
|
+
headers.Authorization = `Bearer ${config.token}`;
|
|
804
|
+
}
|
|
805
|
+
return ky.create({
|
|
806
|
+
prefix: config.baseUrl,
|
|
807
|
+
timeout: config.timeout ?? 3e4,
|
|
808
|
+
credentials: "include",
|
|
809
|
+
retry: {
|
|
810
|
+
limit: config.maxRetries ?? 2,
|
|
811
|
+
statusCodes: [408, 500, 502, 503, 504],
|
|
812
|
+
methods: ["get", "post", "put", "patch", "delete"]
|
|
813
|
+
},
|
|
814
|
+
headers,
|
|
815
|
+
hooks: {
|
|
816
|
+
beforeError: [
|
|
817
|
+
({ error }) => {
|
|
818
|
+
if (error.name === "TimeoutError") {
|
|
819
|
+
throw new RustrakTransportFailure({
|
|
820
|
+
kind: "network",
|
|
821
|
+
message: TIMEOUT_ERROR_MESSAGE,
|
|
822
|
+
reason: "timeout"
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
if (isHTTPError(error)) {
|
|
826
|
+
throw new RustrakTransportFailure(transformHttpError(error));
|
|
827
|
+
}
|
|
828
|
+
throw new RustrakTransportFailure({
|
|
829
|
+
kind: "network",
|
|
830
|
+
message: NETWORK_ERROR_MESSAGE,
|
|
831
|
+
reason: "unreachable"
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
]
|
|
835
|
+
}
|
|
836
|
+
});
|
|
837
|
+
}
|
|
730
838
|
|
|
731
839
|
// src/resources/base.ts
|
|
840
|
+
var TRANSPORT_TYPE_ERROR = /terminated|aborted|socket|network|closed|reset|fetch failed/i;
|
|
841
|
+
function isProgrammingError(error) {
|
|
842
|
+
if (!(error instanceof Error)) {
|
|
843
|
+
return true;
|
|
844
|
+
}
|
|
845
|
+
if (error instanceof ReferenceError || error instanceof RangeError) {
|
|
846
|
+
return true;
|
|
847
|
+
}
|
|
848
|
+
if (error instanceof TypeError) {
|
|
849
|
+
return error.cause === void 0 && !TRANSPORT_TYPE_ERROR.test(error.message);
|
|
850
|
+
}
|
|
851
|
+
return false;
|
|
852
|
+
}
|
|
853
|
+
function classifyBodyFailure(error) {
|
|
854
|
+
if (error instanceof SyntaxError) {
|
|
855
|
+
return {
|
|
856
|
+
kind: "invalid_response",
|
|
857
|
+
message: "The server returned a body that is not valid JSON."
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
if (isProgrammingError(error)) {
|
|
861
|
+
return "rethrow";
|
|
862
|
+
}
|
|
863
|
+
return {
|
|
864
|
+
kind: "network",
|
|
865
|
+
message: NETWORK_ERROR_MESSAGE,
|
|
866
|
+
reason: error instanceof Error && error.name === "TimeoutError" ? "timeout" : "unreachable"
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
function discardBody(response) {
|
|
870
|
+
try {
|
|
871
|
+
void response.body?.cancel().catch(() => {
|
|
872
|
+
});
|
|
873
|
+
} catch {
|
|
874
|
+
}
|
|
875
|
+
}
|
|
732
876
|
var BaseResource = class {
|
|
733
877
|
http;
|
|
734
878
|
constructor(http) {
|
|
735
879
|
this.http = http;
|
|
736
880
|
}
|
|
737
881
|
/**
|
|
738
|
-
* Validate API response against Zod schema
|
|
739
|
-
*
|
|
882
|
+
* Validate an API response against its Zod schema.
|
|
883
|
+
*
|
|
884
|
+
* Failure is `invalid_response`: "our own response schema did not match",
|
|
885
|
+
* never "the user's input was rejected". No Zod issues are attached: they
|
|
886
|
+
* embed the offending response data.
|
|
740
887
|
*/
|
|
741
888
|
validate(data, schema) {
|
|
742
889
|
const result = schema.safeParse(data);
|
|
743
890
|
if (!result.success) {
|
|
744
|
-
|
|
891
|
+
return Err({
|
|
892
|
+
kind: "invalid_response",
|
|
893
|
+
message: "The server response did not match the expected schema."
|
|
894
|
+
});
|
|
895
|
+
}
|
|
896
|
+
return Ok(result.data);
|
|
897
|
+
}
|
|
898
|
+
/**
|
|
899
|
+
* Validate caller-supplied input before it reaches the network.
|
|
900
|
+
*
|
|
901
|
+
* Failure is `invalid_request` and has no `status`: nothing was sent.
|
|
902
|
+
*/
|
|
903
|
+
validateInput(input, schema) {
|
|
904
|
+
const result = schema.safeParse(input);
|
|
905
|
+
if (!result.success) {
|
|
906
|
+
return Err({
|
|
907
|
+
kind: "invalid_request",
|
|
908
|
+
message: "The request input did not match the expected schema."
|
|
909
|
+
});
|
|
745
910
|
}
|
|
746
|
-
return result.data;
|
|
911
|
+
return Ok(result.data);
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* The boundary. Runs `send`, converts a transport failure into an `Err`, and
|
|
915
|
+
* hands the `Response` to `read`.
|
|
916
|
+
*
|
|
917
|
+
* Anything thrown that is not the internal carrier is a programming error and
|
|
918
|
+
* is rethrown.
|
|
919
|
+
*/
|
|
920
|
+
async requestResponse(send, read) {
|
|
921
|
+
let response;
|
|
922
|
+
try {
|
|
923
|
+
response = await send();
|
|
924
|
+
} catch (error) {
|
|
925
|
+
if (isTransportFailure(error)) {
|
|
926
|
+
return Err(error.rustrakError);
|
|
927
|
+
}
|
|
928
|
+
throw error;
|
|
929
|
+
}
|
|
930
|
+
return read(response);
|
|
931
|
+
}
|
|
932
|
+
/**
|
|
933
|
+
* Read a JSON body, mapping a failed read onto the right `kind`.
|
|
934
|
+
*
|
|
935
|
+
* Shared with `AuthResource`, which needs the `Set-Cookie` headers off the
|
|
936
|
+
* raw `Response` and so cannot go through {@link BaseResource.request}.
|
|
937
|
+
*/
|
|
938
|
+
async readJson(response) {
|
|
939
|
+
try {
|
|
940
|
+
return Ok(await response.json());
|
|
941
|
+
} catch (error) {
|
|
942
|
+
const failure = classifyBodyFailure(error);
|
|
943
|
+
if (failure === "rethrow") {
|
|
944
|
+
throw error;
|
|
945
|
+
}
|
|
946
|
+
return Err(failure);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
/** Send a request and validate its JSON body against `schema`. */
|
|
950
|
+
async request(send, schema) {
|
|
951
|
+
return this.requestResponse(send, async (response) => {
|
|
952
|
+
const body = await this.readJson(response);
|
|
953
|
+
if (!body.success) {
|
|
954
|
+
return body;
|
|
955
|
+
}
|
|
956
|
+
return this.validate(body.data, schema);
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
/** Send a request whose response body carries no contract (204, or ignored). */
|
|
960
|
+
async requestVoid(send) {
|
|
961
|
+
return this.requestResponse(send, async (response) => {
|
|
962
|
+
discardBody(response);
|
|
963
|
+
return Ok(void 0);
|
|
964
|
+
});
|
|
747
965
|
}
|
|
748
966
|
};
|
|
749
967
|
|
|
@@ -773,46 +991,56 @@ var AgentsResource = class extends BaseResource {
|
|
|
773
991
|
* Time-bucketed count of agent-run spans (`gen_ai.operation.type:agent`).
|
|
774
992
|
*/
|
|
775
993
|
async getRuns(projectId, options) {
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
994
|
+
return this.request(
|
|
995
|
+
() => this.http.get(`api/projects/${projectId}/agents/runs`, {
|
|
996
|
+
searchParams: timeseriesSearchParams(options)
|
|
997
|
+
}),
|
|
998
|
+
z.array(agentTimeseriesPointSchema)
|
|
999
|
+
);
|
|
780
1000
|
}
|
|
781
1001
|
/**
|
|
782
1002
|
* Time-bucketed avg/p95 duration for `agent`/`ai_client` spans.
|
|
783
1003
|
*/
|
|
784
1004
|
async getDuration(projectId, options) {
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
1005
|
+
return this.request(
|
|
1006
|
+
() => this.http.get(`api/projects/${projectId}/agents/duration`, {
|
|
1007
|
+
searchParams: timeseriesSearchParams(options)
|
|
1008
|
+
}),
|
|
1009
|
+
z.array(agentDurationPointSchema)
|
|
1010
|
+
);
|
|
789
1011
|
}
|
|
790
1012
|
/**
|
|
791
1013
|
* Top models by LLM call count (`gen_ai.operation.type:ai_client`).
|
|
792
1014
|
*/
|
|
793
1015
|
async getModelsByCalls(projectId, options) {
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
1016
|
+
return this.request(
|
|
1017
|
+
() => this.http.get(`api/projects/${projectId}/agents/models/calls`, {
|
|
1018
|
+
searchParams: breakdownSearchParams(options)
|
|
1019
|
+
}),
|
|
1020
|
+
z.array(genAiBreakdownRowSchema)
|
|
1021
|
+
);
|
|
798
1022
|
}
|
|
799
1023
|
/**
|
|
800
1024
|
* Top models by total tokens used (`gen_ai.operation.type:ai_client`).
|
|
801
1025
|
*/
|
|
802
1026
|
async getModelsByTokens(projectId, options) {
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
1027
|
+
return this.request(
|
|
1028
|
+
() => this.http.get(`api/projects/${projectId}/agents/models/tokens`, {
|
|
1029
|
+
searchParams: breakdownSearchParams(options)
|
|
1030
|
+
}),
|
|
1031
|
+
z.array(genAiBreakdownRowSchema)
|
|
1032
|
+
);
|
|
807
1033
|
}
|
|
808
1034
|
/**
|
|
809
1035
|
* Top tools by call count (`gen_ai.operation.type:tool`).
|
|
810
1036
|
*/
|
|
811
1037
|
async getTools(projectId, options) {
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
1038
|
+
return this.request(
|
|
1039
|
+
() => this.http.get(`api/projects/${projectId}/agents/tools`, {
|
|
1040
|
+
searchParams: breakdownSearchParams(options)
|
|
1041
|
+
}),
|
|
1042
|
+
z.array(genAiBreakdownRowSchema)
|
|
1043
|
+
);
|
|
816
1044
|
}
|
|
817
1045
|
/**
|
|
818
1046
|
* Paginated per-trace_id aggregate (duration, tokens, tool usage) across
|
|
@@ -826,9 +1054,10 @@ var AgentsResource = class extends BaseResource {
|
|
|
826
1054
|
if (options?.per_page) {
|
|
827
1055
|
searchParams.per_page = String(options.per_page);
|
|
828
1056
|
}
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
1057
|
+
return this.request(
|
|
1058
|
+
() => this.http.get(`api/projects/${projectId}/agents/traces`, {
|
|
1059
|
+
searchParams
|
|
1060
|
+
}),
|
|
832
1061
|
offsetPaginatedResponseSchema(agentTraceSummarySchema)
|
|
833
1062
|
);
|
|
834
1063
|
}
|
|
@@ -838,52 +1067,83 @@ var AlertIntegrationsResource = class extends BaseResource {
|
|
|
838
1067
|
* List all alert integrations
|
|
839
1068
|
*/
|
|
840
1069
|
async list() {
|
|
841
|
-
|
|
842
|
-
|
|
1070
|
+
return this.request(
|
|
1071
|
+
() => this.http.get("api/integrations"),
|
|
1072
|
+
z.array(alertIntegrationSchema)
|
|
1073
|
+
);
|
|
843
1074
|
}
|
|
844
1075
|
/**
|
|
845
1076
|
* Get a single alert integration by ID
|
|
846
1077
|
*/
|
|
847
1078
|
async get(id) {
|
|
848
|
-
|
|
849
|
-
|
|
1079
|
+
return this.request(
|
|
1080
|
+
() => this.http.get(`api/integrations/${id}`),
|
|
1081
|
+
alertIntegrationSchema
|
|
1082
|
+
);
|
|
850
1083
|
}
|
|
851
1084
|
/**
|
|
852
1085
|
* Create a new alert integration
|
|
853
1086
|
*/
|
|
854
1087
|
async create(input) {
|
|
855
|
-
const validatedInput = this.
|
|
856
|
-
|
|
857
|
-
|
|
1088
|
+
const validatedInput = this.validateInput(
|
|
1089
|
+
input,
|
|
1090
|
+
createAlertIntegrationSchema
|
|
1091
|
+
);
|
|
1092
|
+
if (!validatedInput.success) {
|
|
1093
|
+
return validatedInput;
|
|
1094
|
+
}
|
|
1095
|
+
return this.request(
|
|
1096
|
+
() => this.http.post("api/integrations", { json: validatedInput.data }),
|
|
1097
|
+
alertIntegrationSchema
|
|
1098
|
+
);
|
|
858
1099
|
}
|
|
859
1100
|
/**
|
|
860
1101
|
* Update an existing alert integration
|
|
861
1102
|
*/
|
|
862
1103
|
async update(id, input) {
|
|
863
|
-
const validatedInput = this.
|
|
864
|
-
|
|
865
|
-
|
|
1104
|
+
const validatedInput = this.validateInput(
|
|
1105
|
+
input,
|
|
1106
|
+
updateAlertIntegrationSchema
|
|
1107
|
+
);
|
|
1108
|
+
if (!validatedInput.success) {
|
|
1109
|
+
return validatedInput;
|
|
1110
|
+
}
|
|
1111
|
+
return this.request(
|
|
1112
|
+
() => this.http.patch(`api/integrations/${id}`, {
|
|
1113
|
+
json: validatedInput.data
|
|
1114
|
+
}),
|
|
1115
|
+
alertIntegrationSchema
|
|
1116
|
+
);
|
|
866
1117
|
}
|
|
867
1118
|
/**
|
|
868
1119
|
* Delete an alert integration
|
|
869
1120
|
*/
|
|
870
1121
|
async delete(id) {
|
|
871
|
-
|
|
1122
|
+
return this.requestVoid(() => this.http.delete(`api/integrations/${id}`));
|
|
872
1123
|
}
|
|
873
1124
|
/**
|
|
874
1125
|
* Send a test notification to verify integration configuration.
|
|
875
1126
|
* For Slack bot_token integrations, routingOverride must include `channel`.
|
|
876
1127
|
*/
|
|
877
1128
|
async test(id, routingOverride) {
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
1129
|
+
let body;
|
|
1130
|
+
if (routingOverride !== void 0) {
|
|
1131
|
+
const validatedInput = this.validateInput(
|
|
1132
|
+
{ routing_override: routingOverride },
|
|
1133
|
+
testIntegrationBodySchema
|
|
1134
|
+
);
|
|
1135
|
+
if (!validatedInput.success) {
|
|
1136
|
+
return validatedInput;
|
|
1137
|
+
}
|
|
1138
|
+
body = validatedInput.data;
|
|
1139
|
+
}
|
|
1140
|
+
return this.request(
|
|
1141
|
+
() => this.http.post(
|
|
1142
|
+
`api/integrations/${id}/test`,
|
|
1143
|
+
body !== void 0 ? { json: body } : void 0
|
|
1144
|
+
),
|
|
1145
|
+
testChannelResponseSchema
|
|
1146
|
+
);
|
|
887
1147
|
}
|
|
888
1148
|
};
|
|
889
1149
|
var AlertRulesResource = class extends BaseResource {
|
|
@@ -891,39 +1151,57 @@ var AlertRulesResource = class extends BaseResource {
|
|
|
891
1151
|
* List all alert rules for a project
|
|
892
1152
|
*/
|
|
893
1153
|
async list(projectId) {
|
|
894
|
-
|
|
895
|
-
|
|
1154
|
+
return this.request(
|
|
1155
|
+
() => this.http.get(`api/projects/${projectId}/alert-rules`),
|
|
1156
|
+
z.array(alertRuleSchema)
|
|
1157
|
+
);
|
|
896
1158
|
}
|
|
897
1159
|
/**
|
|
898
1160
|
* Get a single alert rule by ID
|
|
899
1161
|
*/
|
|
900
1162
|
async get(projectId, ruleId) {
|
|
901
|
-
|
|
902
|
-
|
|
1163
|
+
return this.request(
|
|
1164
|
+
() => this.http.get(`api/projects/${projectId}/alert-rules/${ruleId}`),
|
|
1165
|
+
alertRuleSchema
|
|
1166
|
+
);
|
|
903
1167
|
}
|
|
904
1168
|
/**
|
|
905
1169
|
* Create a new alert rule for a project
|
|
906
1170
|
*/
|
|
907
1171
|
async create(projectId, input) {
|
|
908
|
-
const validatedInput = this.
|
|
909
|
-
|
|
910
|
-
|
|
1172
|
+
const validatedInput = this.validateInput(input, createAlertRuleSchema);
|
|
1173
|
+
if (!validatedInput.success) {
|
|
1174
|
+
return validatedInput;
|
|
1175
|
+
}
|
|
1176
|
+
return this.request(
|
|
1177
|
+
() => this.http.post(`api/projects/${projectId}/alert-rules`, {
|
|
1178
|
+
json: validatedInput.data
|
|
1179
|
+
}),
|
|
1180
|
+
alertRuleSchema
|
|
1181
|
+
);
|
|
911
1182
|
}
|
|
912
1183
|
/**
|
|
913
1184
|
* Update an existing alert rule
|
|
914
1185
|
*/
|
|
915
1186
|
async update(projectId, ruleId, input) {
|
|
916
|
-
const validatedInput = this.
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
}
|
|
920
|
-
return this.
|
|
1187
|
+
const validatedInput = this.validateInput(input, updateAlertRuleSchema);
|
|
1188
|
+
if (!validatedInput.success) {
|
|
1189
|
+
return validatedInput;
|
|
1190
|
+
}
|
|
1191
|
+
return this.request(
|
|
1192
|
+
() => this.http.patch(`api/projects/${projectId}/alert-rules/${ruleId}`, {
|
|
1193
|
+
json: validatedInput.data
|
|
1194
|
+
}),
|
|
1195
|
+
alertRuleSchema
|
|
1196
|
+
);
|
|
921
1197
|
}
|
|
922
1198
|
/**
|
|
923
1199
|
* Delete an alert rule
|
|
924
1200
|
*/
|
|
925
1201
|
async delete(projectId, ruleId) {
|
|
926
|
-
|
|
1202
|
+
return this.requestVoid(
|
|
1203
|
+
() => this.http.delete(`api/projects/${projectId}/alert-rules/${ruleId}`)
|
|
1204
|
+
);
|
|
927
1205
|
}
|
|
928
1206
|
/**
|
|
929
1207
|
* List alert history for a project
|
|
@@ -935,12 +1213,18 @@ var AlertRulesResource = class extends BaseResource {
|
|
|
935
1213
|
}
|
|
936
1214
|
const query = searchParams.toString();
|
|
937
1215
|
const url = query ? `api/projects/${projectId}/alert-history?${query}` : `api/projects/${projectId}/alert-history`;
|
|
938
|
-
|
|
939
|
-
return this.validate(data, z.array(alertHistorySchema));
|
|
1216
|
+
return this.request(() => this.http.get(url), z.array(alertHistorySchema));
|
|
940
1217
|
}
|
|
941
1218
|
};
|
|
942
1219
|
|
|
943
1220
|
// src/resources/auth.ts
|
|
1221
|
+
function readSetCookie(response) {
|
|
1222
|
+
if (typeof response.headers.getSetCookie === "function") {
|
|
1223
|
+
return response.headers.getSetCookie();
|
|
1224
|
+
}
|
|
1225
|
+
const folded = response.headers.get("set-cookie");
|
|
1226
|
+
return folded === null ? [] : [folded];
|
|
1227
|
+
}
|
|
944
1228
|
var AuthResource = class extends BaseResource {
|
|
945
1229
|
/**
|
|
946
1230
|
* Register a new user account
|
|
@@ -949,17 +1233,17 @@ var AuthResource = class extends BaseResource {
|
|
|
949
1233
|
* @returns LoginResult with user information and session cookies
|
|
950
1234
|
*/
|
|
951
1235
|
async register(credentials) {
|
|
952
|
-
const validatedInput = this.
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
return
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
1236
|
+
const validatedInput = this.validateInput(
|
|
1237
|
+
credentials,
|
|
1238
|
+
registerRequestSchema
|
|
1239
|
+
);
|
|
1240
|
+
if (!validatedInput.success) {
|
|
1241
|
+
return validatedInput;
|
|
1242
|
+
}
|
|
1243
|
+
return this.requestResponse(
|
|
1244
|
+
() => this.http.post("auth/register", { json: validatedInput.data }),
|
|
1245
|
+
(response) => this.readLoginResult(response)
|
|
1246
|
+
);
|
|
963
1247
|
}
|
|
964
1248
|
/**
|
|
965
1249
|
* Login with email and password
|
|
@@ -968,17 +1252,14 @@ var AuthResource = class extends BaseResource {
|
|
|
968
1252
|
* @returns LoginResult with user information and session cookies
|
|
969
1253
|
*/
|
|
970
1254
|
async login(credentials) {
|
|
971
|
-
const validatedInput = this.
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
}
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
user: authResponse.user,
|
|
980
|
-
cookies
|
|
981
|
-
};
|
|
1255
|
+
const validatedInput = this.validateInput(credentials, loginRequestSchema);
|
|
1256
|
+
if (!validatedInput.success) {
|
|
1257
|
+
return validatedInput;
|
|
1258
|
+
}
|
|
1259
|
+
return this.requestResponse(
|
|
1260
|
+
() => this.http.post("auth/login", { json: validatedInput.data }),
|
|
1261
|
+
(response) => this.readLoginResult(response)
|
|
1262
|
+
);
|
|
982
1263
|
}
|
|
983
1264
|
/**
|
|
984
1265
|
* Logout the current user
|
|
@@ -986,17 +1267,28 @@ var AuthResource = class extends BaseResource {
|
|
|
986
1267
|
* @returns Array of Set-Cookie headers (typically clearing cookies)
|
|
987
1268
|
*/
|
|
988
1269
|
async logout() {
|
|
989
|
-
|
|
990
|
-
|
|
1270
|
+
return this.requestResponse(
|
|
1271
|
+
() => this.http.post("auth/logout"),
|
|
1272
|
+
async (response) => {
|
|
1273
|
+
const cookies = readSetCookie(response);
|
|
1274
|
+
discardBody(response);
|
|
1275
|
+
return Ok(cookies);
|
|
1276
|
+
}
|
|
1277
|
+
);
|
|
991
1278
|
}
|
|
992
1279
|
/**
|
|
993
1280
|
* Get current authenticated user
|
|
994
1281
|
* Requires a valid session cookie
|
|
995
|
-
*
|
|
1282
|
+
*
|
|
1283
|
+
* No session is `{success: false, kind: 'unauthenticated'}`, not a `null`
|
|
1284
|
+
* user: it is the literal reading of the server's 401. Callers must send the
|
|
1285
|
+
* visitor to login on `unauthenticated` **only**. Treating `network` or
|
|
1286
|
+
* `server_error` the same way turns a flaky connection into a login loop.
|
|
1287
|
+
*
|
|
1288
|
+
* @returns The current user, or `unauthenticated` when there is no session
|
|
996
1289
|
*/
|
|
997
1290
|
async getCurrentUser() {
|
|
998
|
-
|
|
999
|
-
return this.validate(data, userSchema);
|
|
1291
|
+
return this.request(() => this.http.get("auth/me"), userSchema);
|
|
1000
1292
|
}
|
|
1001
1293
|
/**
|
|
1002
1294
|
* Get the details of a pending invitation by its token (public endpoint)
|
|
@@ -1005,8 +1297,10 @@ var AuthResource = class extends BaseResource {
|
|
|
1005
1297
|
* @returns Invitation info (email, role, status, expiry)
|
|
1006
1298
|
*/
|
|
1007
1299
|
async getInvitation(token) {
|
|
1008
|
-
|
|
1009
|
-
|
|
1300
|
+
return this.request(
|
|
1301
|
+
() => this.http.get(`auth/invitation/${token}`),
|
|
1302
|
+
invitationInfoSchema
|
|
1303
|
+
);
|
|
1010
1304
|
}
|
|
1011
1305
|
/**
|
|
1012
1306
|
* Accept a pending invitation, creating the user account and logging in
|
|
@@ -1014,17 +1308,33 @@ var AuthResource = class extends BaseResource {
|
|
|
1014
1308
|
* @returns LoginResult with user information and session cookies
|
|
1015
1309
|
*/
|
|
1016
1310
|
async acceptInvitation(input) {
|
|
1017
|
-
const validatedInput = this.
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1311
|
+
const validatedInput = this.validateInput(input, acceptInvitationSchema);
|
|
1312
|
+
if (!validatedInput.success) {
|
|
1313
|
+
return validatedInput;
|
|
1314
|
+
}
|
|
1315
|
+
return this.requestResponse(
|
|
1316
|
+
() => this.http.post("auth/accept-invitation", {
|
|
1317
|
+
json: validatedInput.data
|
|
1318
|
+
}),
|
|
1319
|
+
(response) => this.readLoginResult(response)
|
|
1320
|
+
);
|
|
1321
|
+
}
|
|
1322
|
+
/**
|
|
1323
|
+
* The three session-establishing endpoints share a body and need the
|
|
1324
|
+
* `Set-Cookie` headers off the raw `Response`, which is why they go through
|
|
1325
|
+
* `requestResponse` rather than the plain JSON path.
|
|
1326
|
+
*/
|
|
1327
|
+
async readLoginResult(response) {
|
|
1328
|
+
const cookies = readSetCookie(response);
|
|
1329
|
+
const body = await this.readJson(response);
|
|
1330
|
+
if (!body.success) {
|
|
1331
|
+
return body;
|
|
1332
|
+
}
|
|
1333
|
+
const authResponse = this.validate(body.data, authResponseSchema);
|
|
1334
|
+
if (!authResponse.success) {
|
|
1335
|
+
return authResponse;
|
|
1336
|
+
}
|
|
1337
|
+
return Ok({ user: authResponse.data.user, cookies });
|
|
1028
1338
|
}
|
|
1029
1339
|
};
|
|
1030
1340
|
|
|
@@ -1041,17 +1351,23 @@ var EventsResource = class extends BaseResource {
|
|
|
1041
1351
|
if (options?.cursor) {
|
|
1042
1352
|
searchParams.cursor = options.cursor;
|
|
1043
1353
|
}
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1354
|
+
return this.request(
|
|
1355
|
+
() => this.http.get(`api/projects/${projectId}/issues/${issueId}/events`, {
|
|
1356
|
+
searchParams
|
|
1357
|
+
}),
|
|
1358
|
+
paginatedResponseSchema(eventSchema)
|
|
1359
|
+
);
|
|
1048
1360
|
}
|
|
1049
1361
|
/**
|
|
1050
1362
|
* Get a single event by ID with full details
|
|
1051
1363
|
*/
|
|
1052
1364
|
async get(projectId, issueId, eventId) {
|
|
1053
|
-
|
|
1054
|
-
|
|
1365
|
+
return this.request(
|
|
1366
|
+
() => this.http.get(
|
|
1367
|
+
`api/projects/${projectId}/issues/${issueId}/events/${eventId}`
|
|
1368
|
+
),
|
|
1369
|
+
eventDetailSchema
|
|
1370
|
+
);
|
|
1055
1371
|
}
|
|
1056
1372
|
};
|
|
1057
1373
|
var serverVersionSchema = z.object({
|
|
@@ -1061,8 +1377,10 @@ var serverVersionSchema = z.object({
|
|
|
1061
1377
|
// src/resources/health.ts
|
|
1062
1378
|
var HealthResource = class extends BaseResource {
|
|
1063
1379
|
async getVersion() {
|
|
1064
|
-
|
|
1065
|
-
|
|
1380
|
+
return this.request(
|
|
1381
|
+
() => this.http.get("health/version"),
|
|
1382
|
+
serverVersionSchema
|
|
1383
|
+
);
|
|
1066
1384
|
}
|
|
1067
1385
|
};
|
|
1068
1386
|
|
|
@@ -1073,23 +1391,30 @@ var InvitationsResource = class extends BaseResource {
|
|
|
1073
1391
|
* @param input - Email and global role for the invited user
|
|
1074
1392
|
*/
|
|
1075
1393
|
async create(input) {
|
|
1076
|
-
const validatedInput = this.
|
|
1077
|
-
|
|
1078
|
-
|
|
1394
|
+
const validatedInput = this.validateInput(input, createInvitationSchema);
|
|
1395
|
+
if (!validatedInput.success) {
|
|
1396
|
+
return validatedInput;
|
|
1397
|
+
}
|
|
1398
|
+
return this.request(
|
|
1399
|
+
() => this.http.post("api/invitations", { json: validatedInput.data }),
|
|
1400
|
+
invitationSchema
|
|
1401
|
+
);
|
|
1079
1402
|
}
|
|
1080
1403
|
/**
|
|
1081
1404
|
* List all invitations
|
|
1082
1405
|
*/
|
|
1083
1406
|
async list() {
|
|
1084
|
-
|
|
1085
|
-
|
|
1407
|
+
return this.request(
|
|
1408
|
+
() => this.http.get("api/invitations"),
|
|
1409
|
+
invitationSchema.array()
|
|
1410
|
+
);
|
|
1086
1411
|
}
|
|
1087
1412
|
/**
|
|
1088
1413
|
* Revoke a pending invitation
|
|
1089
1414
|
* @param token - Invitation token to revoke
|
|
1090
1415
|
*/
|
|
1091
1416
|
async revoke(token) {
|
|
1092
|
-
|
|
1417
|
+
return this.requestVoid(() => this.http.delete(`api/invitations/${token}`));
|
|
1093
1418
|
}
|
|
1094
1419
|
};
|
|
1095
1420
|
var IssuesResource = class extends BaseResource {
|
|
@@ -1116,25 +1441,34 @@ var IssuesResource = class extends BaseResource {
|
|
|
1116
1441
|
if (options?.q) {
|
|
1117
1442
|
searchParams.q = options.q;
|
|
1118
1443
|
}
|
|
1119
|
-
|
|
1120
|
-
|
|
1444
|
+
return this.request(
|
|
1445
|
+
() => this.http.get(`api/projects/${projectId}/issues`, { searchParams }),
|
|
1446
|
+
offsetPaginatedResponseSchema(issueSchema)
|
|
1447
|
+
);
|
|
1121
1448
|
}
|
|
1122
1449
|
/**
|
|
1123
1450
|
* Get a single issue by ID
|
|
1124
1451
|
*/
|
|
1125
1452
|
async get(projectId, issueId) {
|
|
1126
|
-
|
|
1127
|
-
|
|
1453
|
+
return this.request(
|
|
1454
|
+
() => this.http.get(`api/projects/${projectId}/issues/${issueId}`),
|
|
1455
|
+
issueSchema
|
|
1456
|
+
);
|
|
1128
1457
|
}
|
|
1129
1458
|
/**
|
|
1130
1459
|
* Update issue state (status, substatus, priority, assignment, …)
|
|
1131
1460
|
*/
|
|
1132
1461
|
async updateState(projectId, issueId, input) {
|
|
1133
|
-
const validatedInput = this.
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
}
|
|
1137
|
-
return this.
|
|
1462
|
+
const validatedInput = this.validateInput(input, updateIssueStateSchema);
|
|
1463
|
+
if (!validatedInput.success) {
|
|
1464
|
+
return validatedInput;
|
|
1465
|
+
}
|
|
1466
|
+
return this.request(
|
|
1467
|
+
() => this.http.patch(`api/projects/${projectId}/issues/${issueId}`, {
|
|
1468
|
+
json: validatedInput.data
|
|
1469
|
+
}),
|
|
1470
|
+
issueSchema
|
|
1471
|
+
);
|
|
1138
1472
|
}
|
|
1139
1473
|
/**
|
|
1140
1474
|
* Resolve an issue in the next release (suppresses regression until a deploy).
|
|
@@ -1148,115 +1482,163 @@ var IssuesResource = class extends BaseResource {
|
|
|
1148
1482
|
* Delete an issue
|
|
1149
1483
|
*/
|
|
1150
1484
|
async delete(projectId, issueId) {
|
|
1151
|
-
|
|
1485
|
+
return this.requestVoid(
|
|
1486
|
+
() => this.http.delete(`api/projects/${projectId}/issues/${issueId}`)
|
|
1487
|
+
);
|
|
1152
1488
|
}
|
|
1153
1489
|
/**
|
|
1154
1490
|
* Bulk-mutate issues (status and/or priority).
|
|
1155
1491
|
*/
|
|
1156
1492
|
async bulkUpdate(projectId, input) {
|
|
1157
|
-
const validatedInput = this.
|
|
1158
|
-
|
|
1159
|
-
|
|
1493
|
+
const validatedInput = this.validateInput(input, bulkUpdateIssuesSchema);
|
|
1494
|
+
if (!validatedInput.success) {
|
|
1495
|
+
return validatedInput;
|
|
1496
|
+
}
|
|
1497
|
+
return this.request(
|
|
1498
|
+
() => this.http.put(`api/projects/${projectId}/issues`, {
|
|
1499
|
+
json: validatedInput.data
|
|
1500
|
+
}),
|
|
1501
|
+
z.object({ updated: z.number().int() })
|
|
1502
|
+
);
|
|
1160
1503
|
}
|
|
1161
1504
|
/**
|
|
1162
1505
|
* Bulk-delete issues.
|
|
1163
1506
|
*/
|
|
1164
1507
|
async bulkDelete(projectId, input) {
|
|
1165
|
-
const validatedInput = this.
|
|
1166
|
-
|
|
1167
|
-
|
|
1508
|
+
const validatedInput = this.validateInput(input, bulkDeleteIssuesSchema);
|
|
1509
|
+
if (!validatedInput.success) {
|
|
1510
|
+
return validatedInput;
|
|
1511
|
+
}
|
|
1512
|
+
return this.request(
|
|
1513
|
+
() => this.http.delete(`api/projects/${projectId}/issues`, {
|
|
1514
|
+
json: validatedInput.data
|
|
1515
|
+
}),
|
|
1516
|
+
z.object({ deleted: z.number().int() })
|
|
1517
|
+
);
|
|
1168
1518
|
}
|
|
1169
1519
|
/**
|
|
1170
1520
|
* List the grouping hashes that map to an issue.
|
|
1171
1521
|
*/
|
|
1172
1522
|
async getHashes(projectId, issueId) {
|
|
1173
|
-
|
|
1174
|
-
|
|
1523
|
+
return this.request(
|
|
1524
|
+
() => this.http.get(`api/projects/${projectId}/issues/${issueId}/hashes`),
|
|
1525
|
+
z.array(issueHashSchema)
|
|
1526
|
+
);
|
|
1175
1527
|
}
|
|
1176
1528
|
/**
|
|
1177
1529
|
* List the distinct values (with counts) for a tag key across the issue.
|
|
1178
1530
|
* Returns a bare list, one entry per value (Sentry-compatible shape).
|
|
1179
1531
|
*/
|
|
1180
1532
|
async getTagValues(projectId, issueId, key) {
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1533
|
+
return this.request(
|
|
1534
|
+
() => this.http.get(
|
|
1535
|
+
`api/projects/${projectId}/issues/${issueId}/tags/${encodeURIComponent(key)}`
|
|
1536
|
+
),
|
|
1537
|
+
z.array(issueTagValueSchema)
|
|
1538
|
+
);
|
|
1185
1539
|
}
|
|
1186
1540
|
/**
|
|
1187
1541
|
* Fetch per-issue aggregates (unique user count + top tags).
|
|
1188
1542
|
*/
|
|
1189
1543
|
async getAggregates(projectId, issueId) {
|
|
1190
|
-
|
|
1191
|
-
|
|
1544
|
+
return this.request(
|
|
1545
|
+
() => this.http.get(`api/projects/${projectId}/issues/${issueId}/aggregates`),
|
|
1546
|
+
issueAggregatesSchema
|
|
1547
|
+
);
|
|
1192
1548
|
}
|
|
1193
1549
|
/**
|
|
1194
1550
|
* Fetch a zero-filled event-count timeseries (24h or 30d).
|
|
1195
1551
|
*/
|
|
1196
1552
|
async getStats(projectId, issueId, window = "24h") {
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1553
|
+
return this.request(
|
|
1554
|
+
() => this.http.get(`api/projects/${projectId}/issues/${issueId}/stats`, {
|
|
1555
|
+
searchParams: { window }
|
|
1556
|
+
}),
|
|
1557
|
+
issueStatsSchema
|
|
1558
|
+
);
|
|
1201
1559
|
}
|
|
1202
1560
|
/**
|
|
1203
1561
|
* List an issue's activity log (status changes, comments/notes, …).
|
|
1204
1562
|
*/
|
|
1205
1563
|
async getActivity(projectId, issueId) {
|
|
1206
|
-
|
|
1207
|
-
|
|
1564
|
+
return this.request(
|
|
1565
|
+
() => this.http.get(`api/projects/${projectId}/issues/${issueId}/activity`),
|
|
1566
|
+
z.array(activityEntrySchema)
|
|
1567
|
+
);
|
|
1208
1568
|
}
|
|
1209
1569
|
/**
|
|
1210
1570
|
* Add a comment (note) to an issue.
|
|
1211
1571
|
*/
|
|
1212
1572
|
async addComment(projectId, issueId, input) {
|
|
1213
|
-
const validatedInput = this.
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
}
|
|
1217
|
-
return this.
|
|
1573
|
+
const validatedInput = this.validateInput(input, createCommentSchema);
|
|
1574
|
+
if (!validatedInput.success) {
|
|
1575
|
+
return validatedInput;
|
|
1576
|
+
}
|
|
1577
|
+
return this.request(
|
|
1578
|
+
() => this.http.post(`api/projects/${projectId}/issues/${issueId}/comments`, {
|
|
1579
|
+
json: validatedInput.data
|
|
1580
|
+
}),
|
|
1581
|
+
activityEntrySchema
|
|
1582
|
+
);
|
|
1218
1583
|
}
|
|
1219
1584
|
/**
|
|
1220
1585
|
* Set or clear the current user's bookmark on an issue.
|
|
1221
1586
|
*/
|
|
1222
1587
|
async setBookmark(projectId, issueId, enabled) {
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1588
|
+
return this.request(
|
|
1589
|
+
() => this.http.put(`api/projects/${projectId}/issues/${issueId}/bookmark`, {
|
|
1590
|
+
json: { enabled }
|
|
1591
|
+
}),
|
|
1592
|
+
z.object({ is_bookmarked: z.boolean() })
|
|
1593
|
+
);
|
|
1227
1594
|
}
|
|
1228
1595
|
/**
|
|
1229
1596
|
* Set or clear the current user's subscription to an issue.
|
|
1230
1597
|
*/
|
|
1231
1598
|
async setSubscription(projectId, issueId, enabled) {
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1599
|
+
return this.request(
|
|
1600
|
+
() => this.http.put(
|
|
1601
|
+
`api/projects/${projectId}/issues/${issueId}/subscription`,
|
|
1602
|
+
{ json: { enabled } }
|
|
1603
|
+
),
|
|
1604
|
+
z.object({ is_subscribed: z.boolean() })
|
|
1605
|
+
);
|
|
1236
1606
|
}
|
|
1237
1607
|
/**
|
|
1238
1608
|
* Mark the issue as seen by the current user.
|
|
1239
1609
|
*/
|
|
1240
1610
|
async markSeen(projectId, issueId) {
|
|
1241
|
-
|
|
1242
|
-
|
|
1611
|
+
return this.request(
|
|
1612
|
+
() => this.http.post(`api/projects/${projectId}/issues/${issueId}/seen`),
|
|
1613
|
+
z.object({ has_seen: z.boolean() })
|
|
1614
|
+
);
|
|
1243
1615
|
}
|
|
1244
1616
|
/**
|
|
1245
1617
|
* List user feedback reports for an issue.
|
|
1246
1618
|
*/
|
|
1247
1619
|
async listUserReports(projectId, issueId) {
|
|
1248
|
-
|
|
1249
|
-
|
|
1620
|
+
return this.request(
|
|
1621
|
+
() => this.http.get(
|
|
1622
|
+
`api/projects/${projectId}/issues/${issueId}/user-reports`
|
|
1623
|
+
),
|
|
1624
|
+
z.array(userReportSchema)
|
|
1625
|
+
);
|
|
1250
1626
|
}
|
|
1251
1627
|
/**
|
|
1252
1628
|
* Attach a user feedback report to an issue.
|
|
1253
1629
|
*/
|
|
1254
1630
|
async createUserReport(projectId, issueId, input) {
|
|
1255
|
-
const validatedInput = this.
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
}
|
|
1259
|
-
return this.
|
|
1631
|
+
const validatedInput = this.validateInput(input, createUserReportSchema);
|
|
1632
|
+
if (!validatedInput.success) {
|
|
1633
|
+
return validatedInput;
|
|
1634
|
+
}
|
|
1635
|
+
return this.request(
|
|
1636
|
+
() => this.http.post(
|
|
1637
|
+
`api/projects/${projectId}/issues/${issueId}/user-reports`,
|
|
1638
|
+
{ json: validatedInput.data }
|
|
1639
|
+
),
|
|
1640
|
+
userReportSchema
|
|
1641
|
+
);
|
|
1260
1642
|
}
|
|
1261
1643
|
};
|
|
1262
1644
|
|
|
@@ -1280,8 +1662,10 @@ var LogsResource = class extends BaseResource {
|
|
|
1280
1662
|
if (options?.trace_id) {
|
|
1281
1663
|
searchParams.trace_id = options.trace_id;
|
|
1282
1664
|
}
|
|
1283
|
-
|
|
1284
|
-
|
|
1665
|
+
return this.request(
|
|
1666
|
+
() => this.http.get(`api/projects/${projectId}/logs`, { searchParams }),
|
|
1667
|
+
offsetPaginatedResponseSchema(logSchema)
|
|
1668
|
+
);
|
|
1285
1669
|
}
|
|
1286
1670
|
};
|
|
1287
1671
|
|
|
@@ -1292,8 +1676,10 @@ var MembersResource = class extends BaseResource {
|
|
|
1292
1676
|
* @param projectId - ID of the project
|
|
1293
1677
|
*/
|
|
1294
1678
|
async list(projectId) {
|
|
1295
|
-
|
|
1296
|
-
|
|
1679
|
+
return this.request(
|
|
1680
|
+
() => this.http.get(`api/projects/${projectId}/members`),
|
|
1681
|
+
projectMemberSchema.array()
|
|
1682
|
+
);
|
|
1297
1683
|
}
|
|
1298
1684
|
/**
|
|
1299
1685
|
* Add or update a project member
|
|
@@ -1301,10 +1687,15 @@ var MembersResource = class extends BaseResource {
|
|
|
1301
1687
|
* @param input - User ID and per-project role
|
|
1302
1688
|
*/
|
|
1303
1689
|
async upsert(projectId, input) {
|
|
1304
|
-
const validatedInput = this.
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
}
|
|
1690
|
+
const validatedInput = this.validateInput(input, upsertProjectMemberSchema);
|
|
1691
|
+
if (!validatedInput.success) {
|
|
1692
|
+
return validatedInput;
|
|
1693
|
+
}
|
|
1694
|
+
return this.requestVoid(
|
|
1695
|
+
() => this.http.put(`api/projects/${projectId}/members`, {
|
|
1696
|
+
json: validatedInput.data
|
|
1697
|
+
})
|
|
1698
|
+
);
|
|
1308
1699
|
}
|
|
1309
1700
|
/**
|
|
1310
1701
|
* Remove a member from a project
|
|
@@ -1312,7 +1703,9 @@ var MembersResource = class extends BaseResource {
|
|
|
1312
1703
|
* @param userId - ID of the user to remove
|
|
1313
1704
|
*/
|
|
1314
1705
|
async remove(projectId, userId) {
|
|
1315
|
-
|
|
1706
|
+
return this.requestVoid(
|
|
1707
|
+
() => this.http.delete(`api/projects/${projectId}/members/${userId}`)
|
|
1708
|
+
);
|
|
1316
1709
|
}
|
|
1317
1710
|
};
|
|
1318
1711
|
|
|
@@ -1337,37 +1730,51 @@ var ProjectsResource = class extends BaseResource {
|
|
|
1337
1730
|
}
|
|
1338
1731
|
const query = searchParams.toString();
|
|
1339
1732
|
const url = query ? `api/projects?${query}` : "api/projects";
|
|
1340
|
-
|
|
1341
|
-
|
|
1733
|
+
return this.request(
|
|
1734
|
+
() => this.http.get(url),
|
|
1735
|
+
offsetPaginatedResponseSchema(projectSchema)
|
|
1736
|
+
);
|
|
1342
1737
|
}
|
|
1343
1738
|
/**
|
|
1344
1739
|
* Get a single project by ID
|
|
1345
1740
|
*/
|
|
1346
1741
|
async get(id) {
|
|
1347
|
-
|
|
1348
|
-
|
|
1742
|
+
return this.request(
|
|
1743
|
+
() => this.http.get(`api/projects/${id}`),
|
|
1744
|
+
projectSchema
|
|
1745
|
+
);
|
|
1349
1746
|
}
|
|
1350
1747
|
/**
|
|
1351
1748
|
* Create a new project
|
|
1352
1749
|
*/
|
|
1353
1750
|
async create(input) {
|
|
1354
|
-
const validatedInput = this.
|
|
1355
|
-
|
|
1356
|
-
|
|
1751
|
+
const validatedInput = this.validateInput(input, createProjectSchema);
|
|
1752
|
+
if (!validatedInput.success) {
|
|
1753
|
+
return validatedInput;
|
|
1754
|
+
}
|
|
1755
|
+
return this.request(
|
|
1756
|
+
() => this.http.post("api/projects", { json: validatedInput.data }),
|
|
1757
|
+
projectSchema
|
|
1758
|
+
);
|
|
1357
1759
|
}
|
|
1358
1760
|
/**
|
|
1359
1761
|
* Update an existing project
|
|
1360
1762
|
*/
|
|
1361
1763
|
async update(id, input) {
|
|
1362
|
-
const validatedInput = this.
|
|
1363
|
-
|
|
1364
|
-
|
|
1764
|
+
const validatedInput = this.validateInput(input, updateProjectSchema);
|
|
1765
|
+
if (!validatedInput.success) {
|
|
1766
|
+
return validatedInput;
|
|
1767
|
+
}
|
|
1768
|
+
return this.request(
|
|
1769
|
+
() => this.http.patch(`api/projects/${id}`, { json: validatedInput.data }),
|
|
1770
|
+
projectSchema
|
|
1771
|
+
);
|
|
1365
1772
|
}
|
|
1366
1773
|
/**
|
|
1367
1774
|
* Delete a project
|
|
1368
1775
|
*/
|
|
1369
1776
|
async delete(id) {
|
|
1370
|
-
|
|
1777
|
+
return this.requestVoid(() => this.http.delete(`api/projects/${id}`));
|
|
1371
1778
|
}
|
|
1372
1779
|
};
|
|
1373
1780
|
var ReleasesResource = class extends BaseResource {
|
|
@@ -1383,11 +1790,13 @@ var ReleasesResource = class extends BaseResource {
|
|
|
1383
1790
|
if (limit !== void 0) {
|
|
1384
1791
|
searchParams.limit = limit.toString();
|
|
1385
1792
|
}
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1793
|
+
return this.request(
|
|
1794
|
+
() => this.http.get(
|
|
1795
|
+
`api/projects/${projectId}/releases/${encodeURIComponent(release)}/new-issues`,
|
|
1796
|
+
{ searchParams }
|
|
1797
|
+
),
|
|
1798
|
+
z.array(issueSchema)
|
|
1799
|
+
);
|
|
1391
1800
|
}
|
|
1392
1801
|
};
|
|
1393
1802
|
|
|
@@ -1413,9 +1822,10 @@ var SessionsResource = class extends BaseResource {
|
|
|
1413
1822
|
if (options?.per_page) {
|
|
1414
1823
|
searchParams.per_page = String(options.per_page);
|
|
1415
1824
|
}
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1825
|
+
return this.request(
|
|
1826
|
+
() => this.http.get(`api/projects/${projectId}/sessions/stats`, {
|
|
1827
|
+
searchParams
|
|
1828
|
+
}),
|
|
1419
1829
|
offsetPaginatedResponseSchema(releaseHealthRowSchema)
|
|
1420
1830
|
);
|
|
1421
1831
|
}
|
|
@@ -1429,8 +1839,12 @@ var SessionsResource = class extends BaseResource {
|
|
|
1429
1839
|
if (period) {
|
|
1430
1840
|
searchParams.period = period;
|
|
1431
1841
|
}
|
|
1432
|
-
|
|
1433
|
-
|
|
1842
|
+
return this.request(
|
|
1843
|
+
() => this.http.get(`api/projects/${projectId}/sessions/summary`, {
|
|
1844
|
+
searchParams
|
|
1845
|
+
}),
|
|
1846
|
+
sessionSummarySchema
|
|
1847
|
+
);
|
|
1434
1848
|
}
|
|
1435
1849
|
/**
|
|
1436
1850
|
* Get a time-bucketed session trend for a project, aggregated across all
|
|
@@ -1447,8 +1861,12 @@ var SessionsResource = class extends BaseResource {
|
|
|
1447
1861
|
if (interval !== void 0) {
|
|
1448
1862
|
searchParams.interval = interval.toString();
|
|
1449
1863
|
}
|
|
1450
|
-
|
|
1451
|
-
|
|
1864
|
+
return this.request(
|
|
1865
|
+
() => this.http.get(`api/projects/${projectId}/sessions/timeseries`, {
|
|
1866
|
+
searchParams
|
|
1867
|
+
}),
|
|
1868
|
+
sessionTimeseriesSchema
|
|
1869
|
+
);
|
|
1452
1870
|
}
|
|
1453
1871
|
};
|
|
1454
1872
|
|
|
@@ -1459,8 +1877,10 @@ var SourceMapsResource = class extends BaseResource {
|
|
|
1459
1877
|
* Returns the upload URL, chunk size limits, and accepted artifact types.
|
|
1460
1878
|
*/
|
|
1461
1879
|
async getChunkUploadCapability(orgSlug) {
|
|
1462
|
-
|
|
1463
|
-
|
|
1880
|
+
return this.request(
|
|
1881
|
+
() => this.http.get(`api/0/organizations/${orgSlug}/chunk-upload/`),
|
|
1882
|
+
chunkUploadCapabilitySchema
|
|
1883
|
+
);
|
|
1464
1884
|
}
|
|
1465
1885
|
/**
|
|
1466
1886
|
* Upload chunks as multipart/form-data, batching by `chunksPerRequest` (default 64).
|
|
@@ -1469,7 +1889,10 @@ var SourceMapsResource = class extends BaseResource {
|
|
|
1469
1889
|
*/
|
|
1470
1890
|
async uploadChunks(orgSlug, chunks, chunksPerRequest = 64) {
|
|
1471
1891
|
if (!Number.isInteger(chunksPerRequest) || chunksPerRequest <= 0) {
|
|
1472
|
-
|
|
1892
|
+
return Err({
|
|
1893
|
+
kind: "invalid_request",
|
|
1894
|
+
message: "chunksPerRequest must be a positive integer."
|
|
1895
|
+
});
|
|
1473
1896
|
}
|
|
1474
1897
|
for (let i = 0; i < chunks.length; i += chunksPerRequest) {
|
|
1475
1898
|
const batch = chunks.slice(i, i + chunksPerRequest);
|
|
@@ -1477,10 +1900,16 @@ var SourceMapsResource = class extends BaseResource {
|
|
|
1477
1900
|
for (const chunk of batch) {
|
|
1478
1901
|
form.append(chunk.hash, chunk.data);
|
|
1479
1902
|
}
|
|
1480
|
-
await this.
|
|
1481
|
-
|
|
1482
|
-
|
|
1903
|
+
const uploaded = await this.requestVoid(
|
|
1904
|
+
() => this.http.post(`api/0/organizations/${orgSlug}/chunk-upload/`, {
|
|
1905
|
+
body: form
|
|
1906
|
+
})
|
|
1907
|
+
);
|
|
1908
|
+
if (!uploaded.success) {
|
|
1909
|
+
return uploaded;
|
|
1910
|
+
}
|
|
1483
1911
|
}
|
|
1912
|
+
return Ok(void 0);
|
|
1484
1913
|
}
|
|
1485
1914
|
/**
|
|
1486
1915
|
* Trigger assembly of a previously uploaded artifact bundle.
|
|
@@ -1490,17 +1919,28 @@ var SourceMapsResource = class extends BaseResource {
|
|
|
1490
1919
|
* still needs uploading via `uploadChunks`.
|
|
1491
1920
|
*/
|
|
1492
1921
|
async assembleBundle(orgSlug, input) {
|
|
1493
|
-
const
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1922
|
+
const validatedInput = this.validateInput(input, assembleInputSchema);
|
|
1923
|
+
if (!validatedInput.success) {
|
|
1924
|
+
return validatedInput;
|
|
1925
|
+
}
|
|
1926
|
+
return this.request(
|
|
1927
|
+
() => this.http.post(
|
|
1928
|
+
`api/0/organizations/${orgSlug}/artifactbundle/assemble/`,
|
|
1929
|
+
{ json: validatedInput.data }
|
|
1930
|
+
),
|
|
1931
|
+
assembleResponseSchema
|
|
1932
|
+
);
|
|
1497
1933
|
}
|
|
1498
1934
|
/**
|
|
1499
1935
|
* List all source map files uploaded for a project.
|
|
1500
1936
|
*/
|
|
1501
1937
|
async list(orgSlug, projectSlug) {
|
|
1502
|
-
|
|
1503
|
-
|
|
1938
|
+
return this.request(
|
|
1939
|
+
() => this.http.get(
|
|
1940
|
+
`api/0/projects/${orgSlug}/${projectSlug}/files/source-maps/`
|
|
1941
|
+
),
|
|
1942
|
+
listSourceMapsResponseSchema
|
|
1943
|
+
);
|
|
1504
1944
|
}
|
|
1505
1945
|
};
|
|
1506
1946
|
|
|
@@ -1530,8 +1970,10 @@ var SpansResource = class extends BaseResource {
|
|
|
1530
1970
|
if (options?.operation_type) {
|
|
1531
1971
|
searchParams.operation_type = options.operation_type;
|
|
1532
1972
|
}
|
|
1533
|
-
|
|
1534
|
-
|
|
1973
|
+
return this.request(
|
|
1974
|
+
() => this.http.get(`api/projects/${projectId}/spans`, { searchParams }),
|
|
1975
|
+
offsetPaginatedResponseSchema(spanSchema)
|
|
1976
|
+
);
|
|
1535
1977
|
}
|
|
1536
1978
|
};
|
|
1537
1979
|
|
|
@@ -1556,8 +1998,12 @@ var StatsResource = class extends BaseResource {
|
|
|
1556
1998
|
if (interval !== void 0) {
|
|
1557
1999
|
searchParams.interval = interval.toString();
|
|
1558
2000
|
}
|
|
1559
|
-
|
|
1560
|
-
|
|
2001
|
+
return this.request(
|
|
2002
|
+
() => this.http.get(`api/projects/${projectId}/events/stats`, {
|
|
2003
|
+
searchParams
|
|
2004
|
+
}),
|
|
2005
|
+
eventTimeseriesSchema
|
|
2006
|
+
);
|
|
1561
2007
|
}
|
|
1562
2008
|
/**
|
|
1563
2009
|
* Get project-wide counters for a window, each paired with the same counter
|
|
@@ -1572,8 +2018,12 @@ var StatsResource = class extends BaseResource {
|
|
|
1572
2018
|
if (period) {
|
|
1573
2019
|
searchParams.period = period;
|
|
1574
2020
|
}
|
|
1575
|
-
|
|
1576
|
-
|
|
2021
|
+
return this.request(
|
|
2022
|
+
() => this.http.get(`api/projects/${projectId}/stats/summary`, {
|
|
2023
|
+
searchParams
|
|
2024
|
+
}),
|
|
2025
|
+
projectStatsSummarySchema
|
|
2026
|
+
);
|
|
1577
2027
|
}
|
|
1578
2028
|
};
|
|
1579
2029
|
var StorageResource = class extends BaseResource {
|
|
@@ -1582,42 +2032,60 @@ var StorageResource = class extends BaseResource {
|
|
|
1582
2032
|
* whole-DB size, and exact source-map weight.
|
|
1583
2033
|
*/
|
|
1584
2034
|
async getSummary() {
|
|
1585
|
-
|
|
1586
|
-
|
|
2035
|
+
return this.request(
|
|
2036
|
+
() => this.http.get("api/storage/summary"),
|
|
2037
|
+
storageSummarySchema
|
|
2038
|
+
);
|
|
1587
2039
|
}
|
|
1588
2040
|
/**
|
|
1589
2041
|
* Get the per-project storage breakdown (one row per project, including
|
|
1590
2042
|
* empty ones).
|
|
1591
2043
|
*/
|
|
1592
2044
|
async getProjects() {
|
|
1593
|
-
|
|
1594
|
-
|
|
2045
|
+
return this.request(
|
|
2046
|
+
() => this.http.get("api/storage/projects"),
|
|
2047
|
+
z.array(projectStorageSchema)
|
|
2048
|
+
);
|
|
1595
2049
|
}
|
|
1596
2050
|
/**
|
|
1597
2051
|
* Dry-run: count the rows a cleanup would remove. Mutates nothing — use it to
|
|
1598
2052
|
* confirm impact before {@link executeCleanup}.
|
|
1599
2053
|
*/
|
|
1600
2054
|
async previewCleanup(options) {
|
|
1601
|
-
const
|
|
1602
|
-
|
|
1603
|
-
|
|
2055
|
+
const validatedInput = this.validateInput(options, cleanupOptionsSchema);
|
|
2056
|
+
if (!validatedInput.success) {
|
|
2057
|
+
return validatedInput;
|
|
2058
|
+
}
|
|
2059
|
+
return this.request(
|
|
2060
|
+
() => this.http.post("api/storage/cleanup/preview", {
|
|
2061
|
+
json: validatedInput.data
|
|
2062
|
+
}),
|
|
2063
|
+
cleanupCountsSchema
|
|
2064
|
+
);
|
|
1604
2065
|
}
|
|
1605
2066
|
/**
|
|
1606
2067
|
* Execute a cleanup: delete data older than `older_than_days` (optionally
|
|
1607
2068
|
* scoped to one project) and remove any issue left with zero events.
|
|
1608
2069
|
*/
|
|
1609
2070
|
async executeCleanup(options) {
|
|
1610
|
-
const
|
|
1611
|
-
|
|
1612
|
-
|
|
2071
|
+
const validatedInput = this.validateInput(options, cleanupOptionsSchema);
|
|
2072
|
+
if (!validatedInput.success) {
|
|
2073
|
+
return validatedInput;
|
|
2074
|
+
}
|
|
2075
|
+
return this.request(
|
|
2076
|
+
() => this.http.post("api/storage/cleanup", { json: validatedInput.data }),
|
|
2077
|
+
cleanupCountsSchema
|
|
2078
|
+
);
|
|
1613
2079
|
}
|
|
1614
2080
|
/**
|
|
1615
2081
|
* Dry-run for {@link gcSourceMaps}: count the orphaned source-map files and
|
|
1616
2082
|
* bytes a GC would reclaim. Mutates nothing.
|
|
1617
2083
|
*/
|
|
1618
2084
|
async previewGcSourceMaps() {
|
|
1619
|
-
|
|
1620
|
-
|
|
2085
|
+
return this.request(
|
|
2086
|
+
() => this.http.post("api/storage/source-maps/gc/preview"),
|
|
2087
|
+
sourceMapGcResultSchema
|
|
2088
|
+
);
|
|
1621
2089
|
}
|
|
1622
2090
|
/**
|
|
1623
2091
|
* Garbage-collect orphaned source maps: files no longer referenced by any
|
|
@@ -1625,8 +2093,10 @@ var StorageResource = class extends BaseResource {
|
|
|
1625
2093
|
* referenced files.
|
|
1626
2094
|
*/
|
|
1627
2095
|
async gcSourceMaps() {
|
|
1628
|
-
|
|
1629
|
-
|
|
2096
|
+
return this.request(
|
|
2097
|
+
() => this.http.post("api/storage/source-maps/gc"),
|
|
2098
|
+
sourceMapGcResultSchema
|
|
2099
|
+
);
|
|
1630
2100
|
}
|
|
1631
2101
|
};
|
|
1632
2102
|
|
|
@@ -1636,8 +2106,10 @@ var TeamResource = class extends BaseResource {
|
|
|
1636
2106
|
* List all team members (users)
|
|
1637
2107
|
*/
|
|
1638
2108
|
async list() {
|
|
1639
|
-
|
|
1640
|
-
|
|
2109
|
+
return this.request(
|
|
2110
|
+
() => this.http.get("api/team"),
|
|
2111
|
+
teamMemberSchema.array()
|
|
2112
|
+
);
|
|
1641
2113
|
}
|
|
1642
2114
|
/**
|
|
1643
2115
|
* Change a user's global role
|
|
@@ -1645,15 +2117,20 @@ var TeamResource = class extends BaseResource {
|
|
|
1645
2117
|
* @param role - New global role to assign
|
|
1646
2118
|
*/
|
|
1647
2119
|
async updateRole(userId, role) {
|
|
1648
|
-
const body = this.
|
|
1649
|
-
|
|
2120
|
+
const body = this.validateInput({ role }, updateUserRoleSchema);
|
|
2121
|
+
if (!body.success) {
|
|
2122
|
+
return body;
|
|
2123
|
+
}
|
|
2124
|
+
return this.requestVoid(
|
|
2125
|
+
() => this.http.patch(`api/team/${userId}/role`, { json: body.data })
|
|
2126
|
+
);
|
|
1650
2127
|
}
|
|
1651
2128
|
/**
|
|
1652
2129
|
* Permanently remove a user from the instance.
|
|
1653
2130
|
* @param userId - ID of the user to delete
|
|
1654
2131
|
*/
|
|
1655
2132
|
async remove(userId) {
|
|
1656
|
-
|
|
2133
|
+
return this.requestVoid(() => this.http.delete(`api/team/${userId}`));
|
|
1657
2134
|
}
|
|
1658
2135
|
};
|
|
1659
2136
|
|
|
@@ -1663,8 +2140,10 @@ var TokensResource = class extends BaseResource {
|
|
|
1663
2140
|
* List all auth tokens (masked)
|
|
1664
2141
|
*/
|
|
1665
2142
|
async list() {
|
|
1666
|
-
|
|
1667
|
-
|
|
2143
|
+
return this.request(
|
|
2144
|
+
() => this.http.get("api/tokens"),
|
|
2145
|
+
authTokenSchema.array()
|
|
2146
|
+
);
|
|
1668
2147
|
}
|
|
1669
2148
|
/**
|
|
1670
2149
|
* Get a single auth token by ID (full token value).
|
|
@@ -1673,23 +2152,30 @@ var TokensResource = class extends BaseResource {
|
|
|
1673
2152
|
* complete token for GET /api/tokens/{id}.
|
|
1674
2153
|
*/
|
|
1675
2154
|
async get(id) {
|
|
1676
|
-
|
|
1677
|
-
|
|
2155
|
+
return this.request(
|
|
2156
|
+
() => this.http.get(`api/tokens/${id}`),
|
|
2157
|
+
authTokenCreatedSchema
|
|
2158
|
+
);
|
|
1678
2159
|
}
|
|
1679
2160
|
/**
|
|
1680
2161
|
* Create a new auth token
|
|
1681
2162
|
* Note: The full token is only returned once during creation
|
|
1682
2163
|
*/
|
|
1683
2164
|
async create(input) {
|
|
1684
|
-
const validatedInput = this.
|
|
1685
|
-
|
|
1686
|
-
|
|
2165
|
+
const validatedInput = this.validateInput(input, createAuthTokenSchema);
|
|
2166
|
+
if (!validatedInput.success) {
|
|
2167
|
+
return validatedInput;
|
|
2168
|
+
}
|
|
2169
|
+
return this.request(
|
|
2170
|
+
() => this.http.post("api/tokens", { json: validatedInput.data }),
|
|
2171
|
+
authTokenCreatedSchema
|
|
2172
|
+
);
|
|
1687
2173
|
}
|
|
1688
2174
|
/**
|
|
1689
2175
|
* Delete an auth token
|
|
1690
2176
|
*/
|
|
1691
2177
|
async delete(id) {
|
|
1692
|
-
|
|
2178
|
+
return this.requestVoid(() => this.http.delete(`api/tokens/${id}`));
|
|
1693
2179
|
}
|
|
1694
2180
|
};
|
|
1695
2181
|
var TransactionsResource = class extends BaseResource {
|
|
@@ -1719,11 +2205,10 @@ var TransactionsResource = class extends BaseResource {
|
|
|
1719
2205
|
if (options?.release) {
|
|
1720
2206
|
searchParams.release = options.release;
|
|
1721
2207
|
}
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
data,
|
|
2208
|
+
return this.request(
|
|
2209
|
+
() => this.http.get(`api/projects/${projectId}/transactions`, {
|
|
2210
|
+
searchParams
|
|
2211
|
+
}),
|
|
1727
2212
|
offsetPaginatedResponseSchema(transactionSchema)
|
|
1728
2213
|
);
|
|
1729
2214
|
}
|
|
@@ -1731,8 +2216,12 @@ var TransactionsResource = class extends BaseResource {
|
|
|
1731
2216
|
* Get the indexed spans extracted from a transaction, in waterfall order.
|
|
1732
2217
|
*/
|
|
1733
2218
|
async getSpans(projectId, transactionId) {
|
|
1734
|
-
|
|
1735
|
-
|
|
2219
|
+
return this.request(
|
|
2220
|
+
() => this.http.get(
|
|
2221
|
+
`api/projects/${projectId}/transactions/${transactionId}/spans`
|
|
2222
|
+
),
|
|
2223
|
+
z.array(spanSchema)
|
|
2224
|
+
);
|
|
1736
2225
|
}
|
|
1737
2226
|
/**
|
|
1738
2227
|
* Get aggregate performance stats (count, p50/p95/p99 latency, failure rate)
|
|
@@ -1747,100 +2236,43 @@ var TransactionsResource = class extends BaseResource {
|
|
|
1747
2236
|
if (options?.per_page) {
|
|
1748
2237
|
searchParams.per_page = String(options.per_page);
|
|
1749
2238
|
}
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
2239
|
+
return this.request(
|
|
2240
|
+
() => this.http.get(`api/projects/${projectId}/transactions/stats`, {
|
|
2241
|
+
searchParams
|
|
2242
|
+
}),
|
|
1753
2243
|
offsetPaginatedResponseSchema(transactionStatsSchema)
|
|
1754
2244
|
);
|
|
1755
2245
|
}
|
|
1756
2246
|
/**
|
|
1757
2247
|
* Get aggregate stats for a single (transaction name, op) group — a direct
|
|
1758
|
-
* lookup that works regardless of how many groups the project has.
|
|
1759
|
-
*
|
|
2248
|
+
* lookup that works regardless of how many groups the project has. Reports
|
|
2249
|
+
* `not_found` when the group has no transactions.
|
|
1760
2250
|
*/
|
|
1761
2251
|
async getStatForGroup(projectId, name, op) {
|
|
1762
2252
|
const searchParams = { name };
|
|
1763
2253
|
if (op) {
|
|
1764
2254
|
searchParams.op = op;
|
|
1765
2255
|
}
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
2256
|
+
return this.request(
|
|
2257
|
+
() => this.http.get(`api/projects/${projectId}/transactions/stats/group`, {
|
|
2258
|
+
searchParams
|
|
2259
|
+
}),
|
|
2260
|
+
transactionStatsSchema
|
|
2261
|
+
);
|
|
1770
2262
|
}
|
|
1771
2263
|
/**
|
|
1772
2264
|
* Get a single transaction by ID with its full Sentry payload (spans,
|
|
1773
2265
|
* contexts.trace, measurements, tags) for the performance detail view.
|
|
1774
2266
|
*/
|
|
1775
2267
|
async get(projectId, transactionId) {
|
|
1776
|
-
|
|
1777
|
-
|
|
2268
|
+
return this.request(
|
|
2269
|
+
() => this.http.get(
|
|
2270
|
+
`api/projects/${projectId}/transactions/${transactionId}`
|
|
2271
|
+
),
|
|
2272
|
+
transactionDetailSchema
|
|
2273
|
+
);
|
|
1778
2274
|
}
|
|
1779
2275
|
};
|
|
1780
|
-
function transformHttpError(error) {
|
|
1781
|
-
const { response } = error;
|
|
1782
|
-
const status = response.status;
|
|
1783
|
-
let errorMessage = `HTTP ${status} error`;
|
|
1784
|
-
const body = error.data;
|
|
1785
|
-
if (body) {
|
|
1786
|
-
const nested = typeof body.error === "object" ? body.error?.message : body.error;
|
|
1787
|
-
errorMessage = nested || body.message || errorMessage;
|
|
1788
|
-
}
|
|
1789
|
-
switch (status) {
|
|
1790
|
-
case 400:
|
|
1791
|
-
return new BadRequestError(errorMessage);
|
|
1792
|
-
case 401:
|
|
1793
|
-
return new AuthenticationError(errorMessage);
|
|
1794
|
-
case 403:
|
|
1795
|
-
return new AuthorizationError(errorMessage);
|
|
1796
|
-
case 404:
|
|
1797
|
-
return new NotFoundError(errorMessage);
|
|
1798
|
-
case 429: {
|
|
1799
|
-
const retryAfter = response.headers.get("Retry-After");
|
|
1800
|
-
return new RateLimitError(errorMessage, retryAfter ?? void 0);
|
|
1801
|
-
}
|
|
1802
|
-
case 500:
|
|
1803
|
-
case 502:
|
|
1804
|
-
case 503:
|
|
1805
|
-
case 504:
|
|
1806
|
-
return new ServerError(errorMessage, status);
|
|
1807
|
-
default:
|
|
1808
|
-
return new RustrakError(errorMessage, { statusCode: status });
|
|
1809
|
-
}
|
|
1810
|
-
}
|
|
1811
|
-
function createKyInstance(config) {
|
|
1812
|
-
const headers = {
|
|
1813
|
-
"Content-Type": "application/json",
|
|
1814
|
-
...config.headers
|
|
1815
|
-
};
|
|
1816
|
-
if (config.token) {
|
|
1817
|
-
headers.Authorization = `Bearer ${config.token}`;
|
|
1818
|
-
}
|
|
1819
|
-
return ky.create({
|
|
1820
|
-
prefix: config.baseUrl,
|
|
1821
|
-
timeout: config.timeout ?? 3e4,
|
|
1822
|
-
credentials: "include",
|
|
1823
|
-
retry: {
|
|
1824
|
-
limit: config.maxRetries ?? 2,
|
|
1825
|
-
statusCodes: [408, 500, 502, 503, 504],
|
|
1826
|
-
methods: ["get", "post", "put", "patch", "delete"]
|
|
1827
|
-
},
|
|
1828
|
-
headers,
|
|
1829
|
-
hooks: {
|
|
1830
|
-
beforeError: [
|
|
1831
|
-
({ error }) => {
|
|
1832
|
-
if (error.name === "TimeoutError") {
|
|
1833
|
-
throw new NetworkError("Request timed out", error);
|
|
1834
|
-
}
|
|
1835
|
-
if (isHTTPError(error)) {
|
|
1836
|
-
throw transformHttpError(error);
|
|
1837
|
-
}
|
|
1838
|
-
throw new NetworkError(error.message, error);
|
|
1839
|
-
}
|
|
1840
|
-
]
|
|
1841
|
-
}
|
|
1842
|
-
});
|
|
1843
|
-
}
|
|
1844
2276
|
|
|
1845
2277
|
// src/client.ts
|
|
1846
2278
|
var RustrakClient = class {
|
|
@@ -1955,6 +2387,6 @@ var RustrakClient = class {
|
|
|
1955
2387
|
}
|
|
1956
2388
|
};
|
|
1957
2389
|
|
|
1958
|
-
export {
|
|
2390
|
+
export { Err, FIELD_ERROR_CODES, NETWORK_ERROR_MESSAGE, Ok, RustrakClient, SERVER_ERROR_MESSAGE, TIMEOUT_ERROR_MESSAGE, isRetryable, mapResult, unwrap, unwrapOr };
|
|
1959
2391
|
//# sourceMappingURL=index.js.map
|
|
1960
2392
|
//# sourceMappingURL=index.js.map
|