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