@sentry/api 0.427.0 → 0.428.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 CHANGED
@@ -176,6 +176,55 @@ const sentry = createSentryClient(
176
176
  const { data, error } = await sentry.listOrganizations();
177
177
  ```
178
178
 
179
+ ### Preparing a raw request
180
+
181
+ Use `sentry.client.prepareRequest` when a consumer needs to inspect a request
182
+ or send it through its own raw transport. It shares the preparation used by
183
+ ordinary SDK requests: instance and per-call configuration, authentication,
184
+ validation, body serialization, and request interceptors.
185
+
186
+ ```ts
187
+ const sentry = createSentryClient({ baseUrl: "https://example.test/sentry" });
188
+ const request = await sentry.client.prepareRequest({
189
+ method: "GET",
190
+ url: "/api/0/organizations/example/events/?field=id&field=title&cursor=old#view",
191
+ query: { cursor: "opaque-next", per_page: 50 },
192
+ });
193
+ // Both field values remain; the old cursor is replaced and the fragment removed.
194
+ const response = await fetch(request);
195
+ // The consumer owns status handling and reading the raw body.
196
+ ```
197
+
198
+ Preparation does not call the configured `fetch` or parse a response. Auth
199
+ providers, validators and request interceptors still run and can have side
200
+ effects; their errors reject unchanged. The returned native `Request` includes
201
+ the resolved options and request-interceptor changes. Its signal remains linked
202
+ to the caller's unless an interceptor replaces or clears it. Send it directly
203
+ with the chosen transport; calling `client.request` again would repeat preparation.
204
+ Reading `request.clone()` leaves its body available for dispatch. A custom fetch or
205
+ browser adapter can still add credentials, CSRF headers or routing at dispatch.
206
+
207
+ For endpoints with an existing query, serialized query keys replace all existing
208
+ occurrences of those keys. Explicit `null` input keys also remove existing values,
209
+ even with custom serializers; the serialized output can then add them back.
210
+ Unrelated repeated parameters and their encoding are retained, as is custom
211
+ query-serializer output. The default serializer omits `null` and `undefined`:
212
+ `null` clears the original value, while `undefined` leaves it unchanged.
213
+ Literal URL fragments are removed; encoded `%23` values are retained. These
214
+ rules also apply to ordinary requests through the same URL builder.
215
+
216
+ Use `bodySerializer: null` for an already serialized string, `FormData`, or
217
+ another native body. For `FormData`, also clear the default JSON content type
218
+ with `headers: { "Content-Type": null }` so `Request` supplies its boundary.
219
+ Otherwise the configured serializer still applies. Native
220
+ `Request` construction can add a content type for strings or form data; prepared
221
+ headers describe that request, not a consumer's earlier input or redacted preview.
222
+
223
+ Pass decoded server cursors and explicit page sizes as query parameters. The SDK
224
+ does not interpret bookmark formats, select navigation directions or store
225
+ history. Existing custom transports accepted by generated operations do not
226
+ have to implement `prepareRequest`; the factory's concrete transport adds it.
227
+
179
228
  ### Cancellation and custom fetch
180
229
 
181
230
  Reuse the client and supply an `AbortSignal` for each operation. The caller owns the signal, whether it comes from a command, an MCP tool call, or a query library:
@@ -1,2 +1,7 @@
1
- import type { Client, Config } from './types.gen';
2
- export declare const createClient: (config?: Config) => Client;
1
+ import type { Client, Config, RequestOptions } from './types.gen';
2
+ /** The concrete SDK transport adds preparation without requiring it from custom Clients. */
3
+ export type PreparedClient = Client & {
4
+ /** Prepare a native Request using configured auth, serializers and request interceptors, without calling fetch. */
5
+ prepareRequest(options: RequestOptions & Pick<Required<RequestOptions>, 'method'>): Promise<Request>;
6
+ };
7
+ export declare const createClient: (config?: Config) => PreparedClient;
@@ -4,5 +4,6 @@ export { formDataBodySerializer, jsonBodySerializer, urlSearchParamsBodySerializ
4
4
  export { buildClientParams } from '../core/params.gen';
5
5
  export { serializeQueryKeyValue } from '../core/queryKeySerializer.gen';
6
6
  export { createClient } from './client.gen';
7
+ export type { PreparedClient } from './client.gen';
7
8
  export type { Client, ClientOptions, Config, CreateClientConfig, Options, RequestOptions, RequestResult, ResolvedRequestOptions, ResponseStyle, TDataShape, } from './types.gen';
8
9
  export { createConfig, mergeHeaders } from './utils.gen';
@@ -9,4 +9,4 @@ import type { ClientOptions as ClientOptions2 } from './types.gen';
9
9
  * to ensure your client always has the correct values.
10
10
  */
11
11
  export type CreateClientConfig<T extends ClientOptions = ClientOptions2> = (override?: Config<ClientOptions & T>) => Config<Required<ClientOptions> & T>;
12
- export declare const client: import("./client").Client;
12
+ export declare const client: import("./client").PreparedClient;
package/dist/index.js CHANGED
@@ -406,10 +406,21 @@ var getUrl = ({
406
406
  if (search.startsWith("?")) {
407
407
  search = search.substring(1);
408
408
  }
409
- if (search) {
410
- url += `?${search}`;
411
- }
412
- return url;
409
+ url = url.split("#", 1)[0];
410
+ const queryIndex = url.indexOf("?");
411
+ const pathname = queryIndex === -1 ? url : url.slice(0, queryIndex);
412
+ const existing = queryIndex === -1 ? "" : url.slice(queryIndex + 1);
413
+ const replaced = new Set(new URLSearchParams("?" + search).keys());
414
+ for (const [key, value] of Object.entries(query ?? {})) {
415
+ if (value === null)
416
+ replaced.add(key);
417
+ }
418
+ const retained = existing.split("&").filter((part) => {
419
+ const key = new URLSearchParams("?" + part).keys().next().value;
420
+ return part !== "" && (key === undefined || !replaced.has(key));
421
+ });
422
+ const combined = [...retained, search].filter(Boolean).join("&");
423
+ return pathname + (combined ? `?${combined}` : "");
413
424
  };
414
425
  function getValidRequestBody(options) {
415
426
  const hasBody = options.body !== undefined;
@@ -702,7 +713,7 @@ var createClient = (config = {}) => {
702
713
  const url = buildUrl(opts);
703
714
  return { opts, url };
704
715
  };
705
- const request = async (options) => {
716
+ const prepare = async (options) => {
706
717
  const { opts, url } = await beforeRequest(options);
707
718
  const requestInit = {
708
719
  redirect: "follow",
@@ -715,6 +726,11 @@ var createClient = (config = {}) => {
715
726
  request2 = await fn(request2, opts);
716
727
  }
717
728
  }
729
+ return { request: request2, opts };
730
+ };
731
+ const prepareRequest = async (options) => (await prepare(options)).request;
732
+ const request = async (options) => {
733
+ const { request: request2, opts } = await prepare(options);
718
734
  const _fetch = opts.fetch;
719
735
  let response;
720
736
  try {
@@ -840,6 +856,7 @@ var createClient = (config = {}) => {
840
856
  post: makeMethodFn("POST"),
841
857
  put: makeMethodFn("PUT"),
842
858
  request,
859
+ prepareRequest,
843
860
  setConfig,
844
861
  sse: {
845
862
  connect: makeSseFn("CONNECT"),
@@ -8,7 +8,7 @@ import type * as types from './types.gen';
8
8
  * Each method keeps the standalone operation's result and request options.
9
9
  */
10
10
  export declare function createSentryClient(config?: Config): {
11
- readonly client: import("./client").Client;
11
+ readonly client: import("./client").PreparedClient;
12
12
  /**
13
13
  * List Your Organizations
14
14
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/api",
3
- "version": "0.427.0",
3
+ "version": "0.428.0",
4
4
  "description": "Official auto-generated TypeScript client for the Sentry public REST API",
5
5
  "keywords": [
6
6
  "sentry",