@rustrak/client 0.19.0 → 0.20.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
@@ -286,9 +286,11 @@ Every method, grouped as it hangs off the client (`client.issues.list(...)`).
286
286
 
287
287
  | Method | Endpoint | Description |
288
288
  |---|---|---|
289
+ | `events.downloadAttachment({ path })` | `GET /api/projects/{project_id}/attachments/{attachment_id}` | Downloads an attachment. |
289
290
  | `events.get({ path })` | `GET /api/projects/{project_id}/issues/{issue_id}/events/{event_id}` | Gets a single event with full data |
290
291
  | `events.getBySentryId({ path })` | `GET /api/projects/{project_id}/events/sentry/{event_id}` | Resolve the ID returned by a Sentry SDK without already knowing the issue. |
291
292
  | `events.list({ path, query? })` | `GET /api/projects/{project_id}/issues/{issue_id}/events` | Lists events for an issue with cursor-based pagination |
293
+ | `events.listAttachments({ path })` | `GET /api/projects/{project_id}/issues/{issue_id}/events/{event_id}/attachments` | Lists the files sent with an event, such as a feedback's screenshot. |
292
294
 
293
295
  ### GitHub
294
296
 
@@ -332,6 +334,7 @@ Every method, grouped as it hangs off the client (`client.issues.list(...)`).
332
334
 
333
335
  | Method | Endpoint | Description |
334
336
  |---|---|---|
337
+ | `feedback.list({ path, query? })` | `GET /api/projects/{project_id}/feedback` | Lists user feedback with what each user submitted. |
335
338
  | `issues.bulkDelete({ path, body })` | `DELETE /api/projects/{project_id}/issues` | Bulk delete by ids or filter |
336
339
  | `issues.bulkUpdate({ path, body })` | `PUT /api/projects/{project_id}/issues` | Bulk mutate |
337
340
  | `issues.createComment({ path, body })` | `POST /api/projects/{project_id}/issues/{issue_id}/comments` | Add a note. |
@@ -344,7 +347,7 @@ Every method, grouped as it hangs off the client (`client.issues.list(...)`).
344
347
  | `issues.getStats({ path, query? })` | `GET /api/projects/{project_id}/issues/{issue_id}/stats` | Zero-filled event-count timeseries. |
345
348
  | `issues.getTagValues({ path })` | `GET /api/projects/{project_id}/issues/{issue_id}/tags/{key}` | Lists the distinct values (with counts) for a tag key across the issue. |
346
349
  | `issues.list({ path, query? })` | `GET /api/projects/{project_id}/issues` | Lists issues for a project with offset-based pagination |
347
- | `issues.listUserReports({ path })` | `GET /api/projects/{project_id}/issues/{issue_id}/user-reports` | List user feedback for an issue. |
350
+ | `issues.listUserReports({ path, query? })` | `GET /api/projects/{project_id}/issues/{issue_id}/user-reports` | List user feedback for an issue. |
348
351
  | `issues.markSeen({ path })` | `POST /api/projects/{project_id}/issues/{issue_id}/seen` | Mark the issue as seen by the current user. |
349
352
  | `issues.setBookmark({ path, body })` | `PUT /api/projects/{project_id}/issues/{issue_id}/bookmark` | Set/clear the per-user bookmark. |
350
353
  | `issues.setSubscription({ path, body })` | `PUT /api/projects/{project_id}/issues/{issue_id}/subscription` | Set/clear the per-user subscription. |
@@ -409,6 +412,20 @@ Every method, grouped as it hangs off the client (`client.issues.list(...)`).
409
412
  |---|---|---|
410
413
  | `schedules.preview({ body })` | `POST /api/schedules/preview` | Validates a schedule and lists its next five runs from now, so no client ever parses a crontab itself. |
411
414
 
415
+ ### Sentry API
416
+
417
+ | Method | Endpoint | Description |
418
+ |---|---|---|
419
+ | `sentry.getIssue({ path })` | `GET /api/0/issues/{issue_id}/` | One issue with its releases and its 24h and 30d series (Sentry's `GroupDetailsEndpoint`). |
420
+ | `sentry.getLatestEvent({ path })` | `GET /api/0/issues/{issue_id}/events/latest/` | The issue's most recent event (Sentry's `GroupEventDetailsEndpoint`, `issues/endpoints/group_event_details.py`). |
421
+ | `sentry.listIssues({ path, query? })` | `GET /api/0/projects/{org_slug}/{project_slug}/issues/` | A project's issues, filtered by `query`, sorted by `sort` and paginated by `cursor` (Sentry's `ProjectGroupIndexEndpoint`, `issues/endpoints/project_group_index.py`). |
422
+ | `sentry.listOrganizations()` | `GET /api/0/organizations/` | The organizations the token belongs to (Sentry's `OrganizationIndexEndpoint`): always the one synthetic org. |
423
+ | `sentry.listProjects({ query? })` | `GET /api/0/projects/` | The projects the token can see, newest first (Sentry's `ProjectIndexEndpoint`, `core/endpoints/project_index.py`). |
424
+ | `sentry.listRepos({ path })` | `GET /api/0/organizations/{org_slug}/repos/` | The code repositories connected to the organization (Sentry's `OrganizationRepositoriesEndpoint`). |
425
+ | `sentry.openIssue({ path })` | `GET /{org_slug}/{project_slug}/issues/{issue_id}` | The issue page GitLab's "View in Sentry" opens: Sentry redirects this legacy path to the issue (`static/app/router/routes.tsx`), Rustrak to its dashboard. |
426
+ | `sentry.submitUserFeedback({ path, body })` | `POST /api/0/projects/{org_slug}/{project_slug}/user-feedback/` | Submit a user report about an error event (Sentry's `ProjectUserReportsEndpoint`, `feedback/endpoints/project_user_reports.py`). |
427
+ | `sentry.updateIssue({ path, body })` | `PUT /api/0/issues/{issue_id}/` | Sets an issue's status and returns the issue (Sentry's `GroupDetailsEndpoint.put`). |
428
+
412
429
  ### Sessions
413
430
 
414
431
  | Method | Endpoint | Description |
package/dist/client.cjs CHANGED
@@ -5,6 +5,7 @@ const require_result = require("./result.cjs");
5
5
  const require_http = require("./utils/http.cjs");
6
6
  let zod = require("zod");
7
7
  //#region src/client.ts
8
+ const BINARY = /* @__PURE__ */ new Set(["events.downloadAttachment"]);
8
9
  /**
9
10
  * Main Rustrak API client. Every method returns a `Result`; nothing throws for
10
11
  * an expected failure.
@@ -47,6 +48,7 @@ function createApi(config) {
47
48
  methods[method] = async (options = {}) => toResult(await resource[method]({
48
49
  ...options,
49
50
  headers: options.headers instanceof Headers || Array.isArray(options.headers) ? Object.fromEntries(new Headers(options.headers)) : options.headers,
51
+ ...BINARY.has(`${name}.${method}`) && { parseAs: "blob" },
50
52
  throwOnError: false
51
53
  }));
52
54
  }
@@ -1 +1 @@
1
- {"version":3,"file":"client.cjs","names":["Rustrak","createClient","createConfig","createFetch","Ok","isTransportFailure","Err","transformHttpError","ZodError"],"sources":["../src/client.ts"],"sourcesContent":["import { ZodError } from 'zod';\nimport type { ClientConfig } from './config.js';\nimport type { RustrakError } from './errors.js';\nimport { createClient, createConfig } from './generated/client/index.js';\nimport { Rustrak } from './generated/sdk.gen.js';\nimport { Err, Ok, type Result } from './result.js';\nimport {\n createFetch,\n isTransportFailure,\n transformHttpError,\n} from './utils/http.js';\n\n/** What a caller may pass: the request's own parts, never client plumbing. */\ntype RequestKeys = 'path' | 'query' | 'body' | 'headers' | 'signal';\n\ntype Call<F> = F extends (options: infer O) => infer R\n ? (\n ...args: {} extends Pick<O, Extract<keyof O, RequestKeys>>\n ? [options?: Pick<O, Extract<keyof O, RequestKeys>>]\n : [options: Pick<O, Extract<keyof O, RequestKeys>>]\n ) => Promise<Result<Data<Awaited<R>>, RustrakError>>\n : never;\n\n/** The success half of the generated `{ data, error }` union. */\ntype Data<R> =\n Extract<R, { error: undefined }> extends { data: infer D } ? D : never;\n\ntype Resource<T> = { readonly [M in keyof T]: Call<T[M]> };\n\n/**\n * Every operation in `openapi.json`, grouped by tag:\n * `client.issues.list({ path: { project_id } })`.\n *\n * Generated in `src/generated/`; this file only changes what a call returns.\n */\nexport type RustrakClient = {\n readonly [R in keyof Rustrak]: Resource<Rustrak[R]>;\n};\n\n/**\n * Main Rustrak API client. Every method returns a `Result`; nothing throws for\n * an expected failure.\n *\n * @example\n * ```typescript\n * const client = new RustrakClient({\n * baseUrl: 'http://localhost:8080',\n * token: 'your-api-token',\n * });\n *\n * const issues = await client.issues.list({ path: { project_id: 1 } });\n * if (issues.success) console.log(issues.data.items);\n * ```\n */\nexport const RustrakClient = class {\n constructor(config: ClientConfig) {\n // biome-ignore lint/correctness/noConstructorReturn: the instance is the generated SDK with every method wrapped\n return Object.setPrototypeOf(createApi(config), new.target.prototype);\n }\n} as unknown as new (\n config: ClientConfig,\n) => RustrakClient;\n\nfunction createApi(config: ClientConfig): RustrakClient {\n const sdk = new Rustrak({\n client: createClient(\n createConfig({\n baseUrl: config.baseUrl,\n credentials: 'include',\n fetch: createFetch(config),\n // Every 2xx in the spec is JSON or empty. `auto` would hand back an\n // HTML page or a stream as a success without validating it.\n parseAs: 'json',\n headers: {\n // Without it a content-negotiating hop can answer with HTML.\n Accept: 'application/json',\n ...config.headers,\n ...(config.token && { Authorization: `Bearer ${config.token}` }),\n },\n }),\n ),\n });\n\n const api: Record<string, Record<string, unknown>> = {};\n for (const name of Object.getOwnPropertyNames(Rustrak.prototype)) {\n if (name === 'constructor') continue;\n const resource = sdk[name as keyof Rustrak] as unknown as Record<\n string,\n (options: object) => Promise<Outcome>\n >;\n const methods: Record<string, unknown> = {};\n for (const method of Object.getOwnPropertyNames(\n Object.getPrototypeOf(resource),\n )) {\n if (method === 'constructor') continue;\n methods[method] = async (options: { headers?: unknown } = {}) =>\n toResult(\n await resource[method]!({\n ...options,\n // A JSON write spreads these into an object, which keeps nothing\n // of a `Headers` or an array of pairs.\n headers:\n options.headers instanceof Headers ||\n Array.isArray(options.headers)\n ? Object.fromEntries(new Headers(options.headers))\n : options.headers,\n throwOnError: false,\n }),\n );\n }\n api[name] = methods;\n }\n return api as unknown as RustrakClient;\n}\n\ntype Outcome = {\n data?: unknown;\n error?: unknown;\n response?: Response;\n};\n\n/**\n * The boundary: the generated client's `{ data, error, response }` becomes a\n * `Result`.\n *\n * Only failures this file recognises become an `Err`. Anything else, a\n * `TypeError` from a genuine bug, is rethrown so it crashes where it can be\n * debugged instead of being laundered into `{ success: false }`.\n */\nfunction toResult({\n data,\n error,\n response,\n}: Outcome): Result<unknown, RustrakError> {\n if (error === undefined) return Ok(data);\n if (isTransportFailure(error)) return Err(error.rustrakError);\n if (response && !response.ok) {\n // `error` is the parsed body, or its text when it is not JSON.\n return Err(transformHttpError(response, error));\n }\n if (!response && error instanceof ZodError) {\n return Err({\n kind: 'invalid_request',\n message: 'The request input did not match the expected schema.',\n });\n }\n if (response && error instanceof SyntaxError) {\n return Err({\n kind: 'invalid_response',\n message: 'The server returned a body that is not valid JSON.',\n });\n }\n if (response && error instanceof ZodError) {\n // No Zod issues: they embed the offending response data.\n return Err({\n kind: 'invalid_response',\n message: 'The server response did not match the expected schema.',\n });\n }\n throw error;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAsDA,MAAa,gBAAgB,MAAM;CACjC,YAAY,QAAsB;EAEhC,OAAO,OAAO,eAAe,UAAU,MAAM,GAAG,WAAW,SAAS;CACtE;AACF;AAIA,SAAS,UAAU,QAAqC;CACtD,MAAM,MAAM,IAAIA,gBAAAA,QAAQ,EACtB,QAAQC,mBAAAA,aACNC,kBAAAA,aAAa;EACX,SAAS,OAAO;EAChB,aAAa;EACb,OAAOC,aAAAA,YAAY,MAAM;EAGzB,SAAS;EACT,SAAS;GAEP,QAAQ;GACR,GAAG,OAAO;GACV,GAAI,OAAO,SAAS,EAAE,eAAe,UAAU,OAAO,QAAQ;EAChE;CACF,CAAC,CACH,EACF,CAAC;CAED,MAAM,MAA+C,CAAC;CACtD,KAAK,MAAM,QAAQ,OAAO,oBAAoBH,gBAAAA,QAAQ,SAAS,GAAG;EAChE,IAAI,SAAS,eAAe;EAC5B,MAAM,WAAW,IAAI;EAIrB,MAAM,UAAmC,CAAC;EAC1C,KAAK,MAAM,UAAU,OAAO,oBAC1B,OAAO,eAAe,QAAQ,CAChC,GAAG;GACD,IAAI,WAAW,eAAe;GAC9B,QAAQ,UAAU,OAAO,UAAiC,CAAC,MACzD,SACE,MAAM,SAAS,OAAO,CAAE;IACtB,GAAG;IAGH,SACE,QAAQ,mBAAmB,WAC3B,MAAM,QAAQ,QAAQ,OAAO,IACzB,OAAO,YAAY,IAAI,QAAQ,QAAQ,OAAO,CAAC,IAC/C,QAAQ;IACd,cAAc;GAChB,CAAC,CACH;EACJ;EACA,IAAI,QAAQ;CACd;CACA,OAAO;AACT;;;;;;;;;AAgBA,SAAS,SAAS,EAChB,MACA,OACA,YACyC;CACzC,IAAI,UAAU,KAAA,GAAW,OAAOI,eAAAA,GAAG,IAAI;CACvC,IAAIC,aAAAA,mBAAmB,KAAK,GAAG,OAAOC,eAAAA,IAAI,MAAM,YAAY;CAC5D,IAAI,YAAY,CAAC,SAAS,IAExB,OAAOA,eAAAA,IAAIC,aAAAA,mBAAmB,UAAU,KAAK,CAAC;CAEhD,IAAI,CAAC,YAAY,iBAAiBC,IAAAA,UAChC,OAAOF,eAAAA,IAAI;EACT,MAAM;EACN,SAAS;CACX,CAAC;CAEH,IAAI,YAAY,iBAAiB,aAC/B,OAAOA,eAAAA,IAAI;EACT,MAAM;EACN,SAAS;CACX,CAAC;CAEH,IAAI,YAAY,iBAAiBE,IAAAA,UAE/B,OAAOF,eAAAA,IAAI;EACT,MAAM;EACN,SAAS;CACX,CAAC;CAEH,MAAM;AACR"}
1
+ {"version":3,"file":"client.cjs","names":["Rustrak","createClient","createConfig","createFetch","Ok","isTransportFailure","Err","transformHttpError","ZodError"],"sources":["../src/client.ts"],"sourcesContent":["import { ZodError } from 'zod';\nimport type { ClientConfig } from './config.js';\nimport type { RustrakError } from './errors.js';\nimport { createClient, createConfig } from './generated/client/index.js';\nimport { Rustrak } from './generated/sdk.gen.js';\nimport { Err, Ok, type Result } from './result.js';\nimport {\n createFetch,\n isTransportFailure,\n transformHttpError,\n} from './utils/http.js';\n\n/**\n * Operations whose 2xx is a file, not JSON: read as a `Blob`. The spec leaves\n * the body untyped (zod has no binary type), so the type comes from here.\n */\ntype Binary = 'events.downloadAttachment';\nconst BINARY: ReadonlySet<string> = new Set<Binary>([\n 'events.downloadAttachment',\n]);\n\n/** What a caller may pass: the request's own parts, never client plumbing. */\ntype RequestKeys = 'path' | 'query' | 'body' | 'headers' | 'signal';\n\ntype Call<F, Bytes extends boolean> = F extends (options: infer O) => infer R\n ? (\n ...args: {} extends Pick<O, Extract<keyof O, RequestKeys>>\n ? [options?: Pick<O, Extract<keyof O, RequestKeys>>]\n : [options: Pick<O, Extract<keyof O, RequestKeys>>]\n ) => Promise<\n Result<Bytes extends true ? Blob : Data<Awaited<R>>, RustrakError>\n >\n : never;\n\n/** The success half of the generated `{ data, error }` union. */\ntype Data<R> =\n Extract<R, { error: undefined }> extends { data: infer D } ? D : never;\n\ntype Resource<T, Name extends string> = {\n readonly [M in keyof T]: Call<\n T[M],\n `${Name}.${M & string}` extends Binary ? true : false\n >;\n};\n\n/**\n * Every operation in `openapi.json`, grouped by tag:\n * `client.issues.list({ path: { project_id } })`.\n *\n * Generated in `src/generated/`; this file only changes what a call returns.\n */\nexport type RustrakClient = {\n readonly [R in keyof Rustrak]: Resource<Rustrak[R], R & string>;\n};\n\n/**\n * Main Rustrak API client. Every method returns a `Result`; nothing throws for\n * an expected failure.\n *\n * @example\n * ```typescript\n * const client = new RustrakClient({\n * baseUrl: 'http://localhost:8080',\n * token: 'your-api-token',\n * });\n *\n * const issues = await client.issues.list({ path: { project_id: 1 } });\n * if (issues.success) console.log(issues.data.items);\n * ```\n */\nexport const RustrakClient = class {\n constructor(config: ClientConfig) {\n // biome-ignore lint/correctness/noConstructorReturn: the instance is the generated SDK with every method wrapped\n return Object.setPrototypeOf(createApi(config), new.target.prototype);\n }\n} as unknown as new (\n config: ClientConfig,\n) => RustrakClient;\n\nfunction createApi(config: ClientConfig): RustrakClient {\n const sdk = new Rustrak({\n client: createClient(\n createConfig({\n baseUrl: config.baseUrl,\n credentials: 'include',\n fetch: createFetch(config),\n // Every 2xx in the spec is JSON or empty, except the files in\n // `BINARY`. `auto` would hand back an HTML page or a stream as a\n // success without validating it.\n parseAs: 'json',\n headers: {\n // Without it a content-negotiating hop can answer with HTML.\n Accept: 'application/json',\n ...config.headers,\n ...(config.token && { Authorization: `Bearer ${config.token}` }),\n },\n }),\n ),\n });\n\n const api: Record<string, Record<string, unknown>> = {};\n for (const name of Object.getOwnPropertyNames(Rustrak.prototype)) {\n if (name === 'constructor') continue;\n const resource = sdk[name as keyof Rustrak] as unknown as Record<\n string,\n (options: object) => Promise<Outcome>\n >;\n const methods: Record<string, unknown> = {};\n for (const method of Object.getOwnPropertyNames(\n Object.getPrototypeOf(resource),\n )) {\n if (method === 'constructor') continue;\n methods[method] = async (options: { headers?: unknown } = {}) =>\n toResult(\n await resource[method]!({\n ...options,\n // A JSON write spreads these into an object, which keeps nothing\n // of a `Headers` or an array of pairs.\n headers:\n options.headers instanceof Headers ||\n Array.isArray(options.headers)\n ? Object.fromEntries(new Headers(options.headers))\n : options.headers,\n ...(BINARY.has(`${name}.${method}`) && { parseAs: 'blob' }),\n throwOnError: false,\n }),\n );\n }\n api[name] = methods;\n }\n return api as unknown as RustrakClient;\n}\n\ntype Outcome = {\n data?: unknown;\n error?: unknown;\n response?: Response;\n};\n\n/**\n * The boundary: the generated client's `{ data, error, response }` becomes a\n * `Result`.\n *\n * Only failures this file recognises become an `Err`. Anything else, a\n * `TypeError` from a genuine bug, is rethrown so it crashes where it can be\n * debugged instead of being laundered into `{ success: false }`.\n */\nfunction toResult({\n data,\n error,\n response,\n}: Outcome): Result<unknown, RustrakError> {\n if (error === undefined) return Ok(data);\n if (isTransportFailure(error)) return Err(error.rustrakError);\n if (response && !response.ok) {\n // `error` is the parsed body, or its text when it is not JSON.\n return Err(transformHttpError(response, error));\n }\n if (!response && error instanceof ZodError) {\n return Err({\n kind: 'invalid_request',\n message: 'The request input did not match the expected schema.',\n });\n }\n if (response && error instanceof SyntaxError) {\n return Err({\n kind: 'invalid_response',\n message: 'The server returned a body that is not valid JSON.',\n });\n }\n if (response && error instanceof ZodError) {\n // No Zod issues: they embed the offending response data.\n return Err({\n kind: 'invalid_response',\n message: 'The server response did not match the expected schema.',\n });\n }\n throw error;\n}\n"],"mappings":";;;;;;;AAiBA,MAAM,yBAA8B,IAAI,IAAY,CAClD,2BACF,CAAC;;;;;;;;;;;;;;;;AAmDD,MAAa,gBAAgB,MAAM;CACjC,YAAY,QAAsB;EAEhC,OAAO,OAAO,eAAe,UAAU,MAAM,GAAG,WAAW,SAAS;CACtE;AACF;AAIA,SAAS,UAAU,QAAqC;CACtD,MAAM,MAAM,IAAIA,gBAAAA,QAAQ,EACtB,QAAQC,mBAAAA,aACNC,kBAAAA,aAAa;EACX,SAAS,OAAO;EAChB,aAAa;EACb,OAAOC,aAAAA,YAAY,MAAM;EAIzB,SAAS;EACT,SAAS;GAEP,QAAQ;GACR,GAAG,OAAO;GACV,GAAI,OAAO,SAAS,EAAE,eAAe,UAAU,OAAO,QAAQ;EAChE;CACF,CAAC,CACH,EACF,CAAC;CAED,MAAM,MAA+C,CAAC;CACtD,KAAK,MAAM,QAAQ,OAAO,oBAAoBH,gBAAAA,QAAQ,SAAS,GAAG;EAChE,IAAI,SAAS,eAAe;EAC5B,MAAM,WAAW,IAAI;EAIrB,MAAM,UAAmC,CAAC;EAC1C,KAAK,MAAM,UAAU,OAAO,oBAC1B,OAAO,eAAe,QAAQ,CAChC,GAAG;GACD,IAAI,WAAW,eAAe;GAC9B,QAAQ,UAAU,OAAO,UAAiC,CAAC,MACzD,SACE,MAAM,SAAS,OAAO,CAAE;IACtB,GAAG;IAGH,SACE,QAAQ,mBAAmB,WAC3B,MAAM,QAAQ,QAAQ,OAAO,IACzB,OAAO,YAAY,IAAI,QAAQ,QAAQ,OAAO,CAAC,IAC/C,QAAQ;IACd,GAAI,OAAO,IAAI,GAAG,KAAK,GAAG,QAAQ,KAAK,EAAE,SAAS,OAAO;IACzD,cAAc;GAChB,CAAC,CACH;EACJ;EACA,IAAI,QAAQ;CACd;CACA,OAAO;AACT;;;;;;;;;AAgBA,SAAS,SAAS,EAChB,MACA,OACA,YACyC;CACzC,IAAI,UAAU,KAAA,GAAW,OAAOI,eAAAA,GAAG,IAAI;CACvC,IAAIC,aAAAA,mBAAmB,KAAK,GAAG,OAAOC,eAAAA,IAAI,MAAM,YAAY;CAC5D,IAAI,YAAY,CAAC,SAAS,IAExB,OAAOA,eAAAA,IAAIC,aAAAA,mBAAmB,UAAU,KAAK,CAAC;CAEhD,IAAI,CAAC,YAAY,iBAAiBC,IAAAA,UAChC,OAAOF,eAAAA,IAAI;EACT,MAAM;EACN,SAAS;CACX,CAAC;CAEH,IAAI,YAAY,iBAAiB,aAC/B,OAAOA,eAAAA,IAAI;EACT,MAAM;EACN,SAAS;CACX,CAAC;CAEH,IAAI,YAAY,iBAAiBE,IAAAA,UAE/B,OAAOF,eAAAA,IAAI;EACT,MAAM;EACN,SAAS;CACX,CAAC;CAEH,MAAM;AACR"}
package/dist/client.d.cts CHANGED
@@ -3,15 +3,16 @@ import { RustrakError } from "./errors.cjs";
3
3
  import { Rustrak } from "./generated/sdk.gen.cjs";
4
4
  import { Result } from "./result.cjs";
5
5
  //#region src/client.d.ts
6
+ type Binary = 'events.downloadAttachment';
6
7
  type RequestKeys = 'path' | 'query' | 'body' | 'headers' | 'signal';
7
- type Call<F> = F extends ((options: infer O) => infer R) ? (...args: {} extends Pick<O, Extract<keyof O, RequestKeys>> ? [options?: Pick<O, Extract<keyof O, RequestKeys>>] : [options: Pick<O, Extract<keyof O, RequestKeys>>]) => Promise<Result<Data<Awaited<R>>, RustrakError>> : never;
8
+ type Call<F, Bytes extends boolean> = F extends ((options: infer O) => infer R) ? (...args: {} extends Pick<O, Extract<keyof O, RequestKeys>> ? [options?: Pick<O, Extract<keyof O, RequestKeys>>] : [options: Pick<O, Extract<keyof O, RequestKeys>>]) => Promise<Result<Bytes extends true ? Blob : Data<Awaited<R>>, RustrakError>> : never;
8
9
  type Data<R> = Extract<R, {
9
10
  error: undefined;
10
11
  }> extends {
11
12
  data: infer D;
12
13
  } ? D : never;
13
- type Resource<T> = { readonly [M in keyof T]: Call<T[M]>; };
14
- export type RustrakClient = { readonly [R in keyof Rustrak]: Resource<Rustrak[R]>; };
14
+ type Resource<T, Name extends string> = { readonly [M in keyof T]: Call<T[M], `${Name}.${M & string}` extends Binary ? true : false>; };
15
+ export type RustrakClient = { readonly [R in keyof Rustrak]: Resource<Rustrak[R], R & string>; };
15
16
  export declare const RustrakClient: new (config: ClientConfig) => RustrakClient;
16
17
  //#endregion
17
18
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.cts","names":[],"sources":["../src/client.ts"],"mappings":";;;;;KAaK;KAEA,KAAK,KAAK,YAAW,eAAe,YAAY,SAE5C,iBAAiB,KAAK,GAAG,cAAc,GAAG,iBACxC,UAAU,KAAK,GAAG,cAAc,GAAG,kBACnC,SAAS,KAAK,GAAG,cAAc,GAAG,mBACpC,QAAQ,OAAO,KAAK,QAAQ,KAAK;KAIrC,KAAK,KACR,QAAQ;EAAK;;EAA8B,YAAY;IAAM;KAE1D,SAAS,iBAAiB,WAAW,IAAI,KAAK,EAAE;YAQzC,4BACA,WAAW,UAAU,SAAS,QAAQ;qBAkBrC,oBAMX,QAAQ,iBACL"}
1
+ {"version":3,"file":"client.d.cts","names":[],"sources":["../src/client.ts"],"mappings":";;;;;KAgBK;KAMA;KAEA,KAAK,GAAG,yBAAyB,YAAW,eAAe,YAAY,SAEnE,iBAAiB,KAAK,GAAG,cAAc,GAAG,iBACxC,UAAU,KAAK,GAAG,cAAc,GAAG,kBACnC,SAAS,KAAK,GAAG,cAAc,GAAG,mBACpC,QACH,OAAO,qBAAqB,OAAO,KAAK,QAAQ,KAAK;KAKtD,KAAK,KACR,QAAQ;EAAK;;EAA8B,YAAY;IAAM;KAE1D,SAAS,GAAG,mCACL,WAAW,IAAI,KACvB,EAAE,OACC,QAAQ,qBAAqB;YAUxB,4BACA,WAAW,UAAU,SAAS,QAAQ,IAAI;qBAkBzC,oBAMX,QAAQ,iBACL"}
package/dist/client.d.mts CHANGED
@@ -3,15 +3,16 @@ import { RustrakError } from "./errors.mjs";
3
3
  import { Rustrak } from "./generated/sdk.gen.mjs";
4
4
  import { Result } from "./result.mjs";
5
5
  //#region src/client.d.ts
6
+ type Binary = 'events.downloadAttachment';
6
7
  type RequestKeys = 'path' | 'query' | 'body' | 'headers' | 'signal';
7
- type Call<F> = F extends ((options: infer O) => infer R) ? (...args: {} extends Pick<O, Extract<keyof O, RequestKeys>> ? [options?: Pick<O, Extract<keyof O, RequestKeys>>] : [options: Pick<O, Extract<keyof O, RequestKeys>>]) => Promise<Result<Data<Awaited<R>>, RustrakError>> : never;
8
+ type Call<F, Bytes extends boolean> = F extends ((options: infer O) => infer R) ? (...args: {} extends Pick<O, Extract<keyof O, RequestKeys>> ? [options?: Pick<O, Extract<keyof O, RequestKeys>>] : [options: Pick<O, Extract<keyof O, RequestKeys>>]) => Promise<Result<Bytes extends true ? Blob : Data<Awaited<R>>, RustrakError>> : never;
8
9
  type Data<R> = Extract<R, {
9
10
  error: undefined;
10
11
  }> extends {
11
12
  data: infer D;
12
13
  } ? D : never;
13
- type Resource<T> = { readonly [M in keyof T]: Call<T[M]>; };
14
- export type RustrakClient = { readonly [R in keyof Rustrak]: Resource<Rustrak[R]>; };
14
+ type Resource<T, Name extends string> = { readonly [M in keyof T]: Call<T[M], `${Name}.${M & string}` extends Binary ? true : false>; };
15
+ export type RustrakClient = { readonly [R in keyof Rustrak]: Resource<Rustrak[R], R & string>; };
15
16
  export declare const RustrakClient: new (config: ClientConfig) => RustrakClient;
16
17
  //#endregion
17
18
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.mts","names":[],"sources":["../src/client.ts"],"mappings":";;;;;KAaK;KAEA,KAAK,KAAK,YAAW,eAAe,YAAY,SAE5C,iBAAiB,KAAK,GAAG,cAAc,GAAG,iBACxC,UAAU,KAAK,GAAG,cAAc,GAAG,kBACnC,SAAS,KAAK,GAAG,cAAc,GAAG,mBACpC,QAAQ,OAAO,KAAK,QAAQ,KAAK;KAIrC,KAAK,KACR,QAAQ;EAAK;;EAA8B,YAAY;IAAM;KAE1D,SAAS,iBAAiB,WAAW,IAAI,KAAK,EAAE;YAQzC,4BACA,WAAW,UAAU,SAAS,QAAQ;qBAkBrC,oBAMX,QAAQ,iBACL"}
1
+ {"version":3,"file":"client.d.mts","names":[],"sources":["../src/client.ts"],"mappings":";;;;;KAgBK;KAMA;KAEA,KAAK,GAAG,yBAAyB,YAAW,eAAe,YAAY,SAEnE,iBAAiB,KAAK,GAAG,cAAc,GAAG,iBACxC,UAAU,KAAK,GAAG,cAAc,GAAG,kBACnC,SAAS,KAAK,GAAG,cAAc,GAAG,mBACpC,QACH,OAAO,qBAAqB,OAAO,KAAK,QAAQ,KAAK;KAKtD,KAAK,KACR,QAAQ;EAAK;;EAA8B,YAAY;IAAM;KAE1D,SAAS,GAAG,mCACL,WAAW,IAAI,KACvB,EAAE,OACC,QAAQ,qBAAqB;YAUxB,4BACA,WAAW,UAAU,SAAS,QAAQ,IAAI;qBAkBzC,oBAMX,QAAQ,iBACL"}
package/dist/client.mjs CHANGED
@@ -5,6 +5,7 @@ import { Err, Ok } from "./result.mjs";
5
5
  import { createFetch, isTransportFailure, transformHttpError } from "./utils/http.mjs";
6
6
  import { ZodError } from "zod";
7
7
  //#region src/client.ts
8
+ const BINARY = /* @__PURE__ */ new Set(["events.downloadAttachment"]);
8
9
  /**
9
10
  * Main Rustrak API client. Every method returns a `Result`; nothing throws for
10
11
  * an expected failure.
@@ -47,6 +48,7 @@ function createApi(config) {
47
48
  methods[method] = async (options = {}) => toResult(await resource[method]({
48
49
  ...options,
49
50
  headers: options.headers instanceof Headers || Array.isArray(options.headers) ? Object.fromEntries(new Headers(options.headers)) : options.headers,
51
+ ...BINARY.has(`${name}.${method}`) && { parseAs: "blob" },
50
52
  throwOnError: false
51
53
  }));
52
54
  }
@@ -1 +1 @@
1
- {"version":3,"file":"client.mjs","names":[],"sources":["../src/client.ts"],"sourcesContent":["import { ZodError } from 'zod';\nimport type { ClientConfig } from './config.js';\nimport type { RustrakError } from './errors.js';\nimport { createClient, createConfig } from './generated/client/index.js';\nimport { Rustrak } from './generated/sdk.gen.js';\nimport { Err, Ok, type Result } from './result.js';\nimport {\n createFetch,\n isTransportFailure,\n transformHttpError,\n} from './utils/http.js';\n\n/** What a caller may pass: the request's own parts, never client plumbing. */\ntype RequestKeys = 'path' | 'query' | 'body' | 'headers' | 'signal';\n\ntype Call<F> = F extends (options: infer O) => infer R\n ? (\n ...args: {} extends Pick<O, Extract<keyof O, RequestKeys>>\n ? [options?: Pick<O, Extract<keyof O, RequestKeys>>]\n : [options: Pick<O, Extract<keyof O, RequestKeys>>]\n ) => Promise<Result<Data<Awaited<R>>, RustrakError>>\n : never;\n\n/** The success half of the generated `{ data, error }` union. */\ntype Data<R> =\n Extract<R, { error: undefined }> extends { data: infer D } ? D : never;\n\ntype Resource<T> = { readonly [M in keyof T]: Call<T[M]> };\n\n/**\n * Every operation in `openapi.json`, grouped by tag:\n * `client.issues.list({ path: { project_id } })`.\n *\n * Generated in `src/generated/`; this file only changes what a call returns.\n */\nexport type RustrakClient = {\n readonly [R in keyof Rustrak]: Resource<Rustrak[R]>;\n};\n\n/**\n * Main Rustrak API client. Every method returns a `Result`; nothing throws for\n * an expected failure.\n *\n * @example\n * ```typescript\n * const client = new RustrakClient({\n * baseUrl: 'http://localhost:8080',\n * token: 'your-api-token',\n * });\n *\n * const issues = await client.issues.list({ path: { project_id: 1 } });\n * if (issues.success) console.log(issues.data.items);\n * ```\n */\nexport const RustrakClient = class {\n constructor(config: ClientConfig) {\n // biome-ignore lint/correctness/noConstructorReturn: the instance is the generated SDK with every method wrapped\n return Object.setPrototypeOf(createApi(config), new.target.prototype);\n }\n} as unknown as new (\n config: ClientConfig,\n) => RustrakClient;\n\nfunction createApi(config: ClientConfig): RustrakClient {\n const sdk = new Rustrak({\n client: createClient(\n createConfig({\n baseUrl: config.baseUrl,\n credentials: 'include',\n fetch: createFetch(config),\n // Every 2xx in the spec is JSON or empty. `auto` would hand back an\n // HTML page or a stream as a success without validating it.\n parseAs: 'json',\n headers: {\n // Without it a content-negotiating hop can answer with HTML.\n Accept: 'application/json',\n ...config.headers,\n ...(config.token && { Authorization: `Bearer ${config.token}` }),\n },\n }),\n ),\n });\n\n const api: Record<string, Record<string, unknown>> = {};\n for (const name of Object.getOwnPropertyNames(Rustrak.prototype)) {\n if (name === 'constructor') continue;\n const resource = sdk[name as keyof Rustrak] as unknown as Record<\n string,\n (options: object) => Promise<Outcome>\n >;\n const methods: Record<string, unknown> = {};\n for (const method of Object.getOwnPropertyNames(\n Object.getPrototypeOf(resource),\n )) {\n if (method === 'constructor') continue;\n methods[method] = async (options: { headers?: unknown } = {}) =>\n toResult(\n await resource[method]!({\n ...options,\n // A JSON write spreads these into an object, which keeps nothing\n // of a `Headers` or an array of pairs.\n headers:\n options.headers instanceof Headers ||\n Array.isArray(options.headers)\n ? Object.fromEntries(new Headers(options.headers))\n : options.headers,\n throwOnError: false,\n }),\n );\n }\n api[name] = methods;\n }\n return api as unknown as RustrakClient;\n}\n\ntype Outcome = {\n data?: unknown;\n error?: unknown;\n response?: Response;\n};\n\n/**\n * The boundary: the generated client's `{ data, error, response }` becomes a\n * `Result`.\n *\n * Only failures this file recognises become an `Err`. Anything else, a\n * `TypeError` from a genuine bug, is rethrown so it crashes where it can be\n * debugged instead of being laundered into `{ success: false }`.\n */\nfunction toResult({\n data,\n error,\n response,\n}: Outcome): Result<unknown, RustrakError> {\n if (error === undefined) return Ok(data);\n if (isTransportFailure(error)) return Err(error.rustrakError);\n if (response && !response.ok) {\n // `error` is the parsed body, or its text when it is not JSON.\n return Err(transformHttpError(response, error));\n }\n if (!response && error instanceof ZodError) {\n return Err({\n kind: 'invalid_request',\n message: 'The request input did not match the expected schema.',\n });\n }\n if (response && error instanceof SyntaxError) {\n return Err({\n kind: 'invalid_response',\n message: 'The server returned a body that is not valid JSON.',\n });\n }\n if (response && error instanceof ZodError) {\n // No Zod issues: they embed the offending response data.\n return Err({\n kind: 'invalid_response',\n message: 'The server response did not match the expected schema.',\n });\n }\n throw error;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAsDA,MAAa,gBAAgB,MAAM;CACjC,YAAY,QAAsB;EAEhC,OAAO,OAAO,eAAe,UAAU,MAAM,GAAG,WAAW,SAAS;CACtE;AACF;AAIA,SAAS,UAAU,QAAqC;CACtD,MAAM,MAAM,IAAI,QAAQ,EACtB,QAAQ,aACN,aAAa;EACX,SAAS,OAAO;EAChB,aAAa;EACb,OAAO,YAAY,MAAM;EAGzB,SAAS;EACT,SAAS;GAEP,QAAQ;GACR,GAAG,OAAO;GACV,GAAI,OAAO,SAAS,EAAE,eAAe,UAAU,OAAO,QAAQ;EAChE;CACF,CAAC,CACH,EACF,CAAC;CAED,MAAM,MAA+C,CAAC;CACtD,KAAK,MAAM,QAAQ,OAAO,oBAAoB,QAAQ,SAAS,GAAG;EAChE,IAAI,SAAS,eAAe;EAC5B,MAAM,WAAW,IAAI;EAIrB,MAAM,UAAmC,CAAC;EAC1C,KAAK,MAAM,UAAU,OAAO,oBAC1B,OAAO,eAAe,QAAQ,CAChC,GAAG;GACD,IAAI,WAAW,eAAe;GAC9B,QAAQ,UAAU,OAAO,UAAiC,CAAC,MACzD,SACE,MAAM,SAAS,OAAO,CAAE;IACtB,GAAG;IAGH,SACE,QAAQ,mBAAmB,WAC3B,MAAM,QAAQ,QAAQ,OAAO,IACzB,OAAO,YAAY,IAAI,QAAQ,QAAQ,OAAO,CAAC,IAC/C,QAAQ;IACd,cAAc;GAChB,CAAC,CACH;EACJ;EACA,IAAI,QAAQ;CACd;CACA,OAAO;AACT;;;;;;;;;AAgBA,SAAS,SAAS,EAChB,MACA,OACA,YACyC;CACzC,IAAI,UAAU,KAAA,GAAW,OAAO,GAAG,IAAI;CACvC,IAAI,mBAAmB,KAAK,GAAG,OAAO,IAAI,MAAM,YAAY;CAC5D,IAAI,YAAY,CAAC,SAAS,IAExB,OAAO,IAAI,mBAAmB,UAAU,KAAK,CAAC;CAEhD,IAAI,CAAC,YAAY,iBAAiB,UAChC,OAAO,IAAI;EACT,MAAM;EACN,SAAS;CACX,CAAC;CAEH,IAAI,YAAY,iBAAiB,aAC/B,OAAO,IAAI;EACT,MAAM;EACN,SAAS;CACX,CAAC;CAEH,IAAI,YAAY,iBAAiB,UAE/B,OAAO,IAAI;EACT,MAAM;EACN,SAAS;CACX,CAAC;CAEH,MAAM;AACR"}
1
+ {"version":3,"file":"client.mjs","names":[],"sources":["../src/client.ts"],"sourcesContent":["import { ZodError } from 'zod';\nimport type { ClientConfig } from './config.js';\nimport type { RustrakError } from './errors.js';\nimport { createClient, createConfig } from './generated/client/index.js';\nimport { Rustrak } from './generated/sdk.gen.js';\nimport { Err, Ok, type Result } from './result.js';\nimport {\n createFetch,\n isTransportFailure,\n transformHttpError,\n} from './utils/http.js';\n\n/**\n * Operations whose 2xx is a file, not JSON: read as a `Blob`. The spec leaves\n * the body untyped (zod has no binary type), so the type comes from here.\n */\ntype Binary = 'events.downloadAttachment';\nconst BINARY: ReadonlySet<string> = new Set<Binary>([\n 'events.downloadAttachment',\n]);\n\n/** What a caller may pass: the request's own parts, never client plumbing. */\ntype RequestKeys = 'path' | 'query' | 'body' | 'headers' | 'signal';\n\ntype Call<F, Bytes extends boolean> = F extends (options: infer O) => infer R\n ? (\n ...args: {} extends Pick<O, Extract<keyof O, RequestKeys>>\n ? [options?: Pick<O, Extract<keyof O, RequestKeys>>]\n : [options: Pick<O, Extract<keyof O, RequestKeys>>]\n ) => Promise<\n Result<Bytes extends true ? Blob : Data<Awaited<R>>, RustrakError>\n >\n : never;\n\n/** The success half of the generated `{ data, error }` union. */\ntype Data<R> =\n Extract<R, { error: undefined }> extends { data: infer D } ? D : never;\n\ntype Resource<T, Name extends string> = {\n readonly [M in keyof T]: Call<\n T[M],\n `${Name}.${M & string}` extends Binary ? true : false\n >;\n};\n\n/**\n * Every operation in `openapi.json`, grouped by tag:\n * `client.issues.list({ path: { project_id } })`.\n *\n * Generated in `src/generated/`; this file only changes what a call returns.\n */\nexport type RustrakClient = {\n readonly [R in keyof Rustrak]: Resource<Rustrak[R], R & string>;\n};\n\n/**\n * Main Rustrak API client. Every method returns a `Result`; nothing throws for\n * an expected failure.\n *\n * @example\n * ```typescript\n * const client = new RustrakClient({\n * baseUrl: 'http://localhost:8080',\n * token: 'your-api-token',\n * });\n *\n * const issues = await client.issues.list({ path: { project_id: 1 } });\n * if (issues.success) console.log(issues.data.items);\n * ```\n */\nexport const RustrakClient = class {\n constructor(config: ClientConfig) {\n // biome-ignore lint/correctness/noConstructorReturn: the instance is the generated SDK with every method wrapped\n return Object.setPrototypeOf(createApi(config), new.target.prototype);\n }\n} as unknown as new (\n config: ClientConfig,\n) => RustrakClient;\n\nfunction createApi(config: ClientConfig): RustrakClient {\n const sdk = new Rustrak({\n client: createClient(\n createConfig({\n baseUrl: config.baseUrl,\n credentials: 'include',\n fetch: createFetch(config),\n // Every 2xx in the spec is JSON or empty, except the files in\n // `BINARY`. `auto` would hand back an HTML page or a stream as a\n // success without validating it.\n parseAs: 'json',\n headers: {\n // Without it a content-negotiating hop can answer with HTML.\n Accept: 'application/json',\n ...config.headers,\n ...(config.token && { Authorization: `Bearer ${config.token}` }),\n },\n }),\n ),\n });\n\n const api: Record<string, Record<string, unknown>> = {};\n for (const name of Object.getOwnPropertyNames(Rustrak.prototype)) {\n if (name === 'constructor') continue;\n const resource = sdk[name as keyof Rustrak] as unknown as Record<\n string,\n (options: object) => Promise<Outcome>\n >;\n const methods: Record<string, unknown> = {};\n for (const method of Object.getOwnPropertyNames(\n Object.getPrototypeOf(resource),\n )) {\n if (method === 'constructor') continue;\n methods[method] = async (options: { headers?: unknown } = {}) =>\n toResult(\n await resource[method]!({\n ...options,\n // A JSON write spreads these into an object, which keeps nothing\n // of a `Headers` or an array of pairs.\n headers:\n options.headers instanceof Headers ||\n Array.isArray(options.headers)\n ? Object.fromEntries(new Headers(options.headers))\n : options.headers,\n ...(BINARY.has(`${name}.${method}`) && { parseAs: 'blob' }),\n throwOnError: false,\n }),\n );\n }\n api[name] = methods;\n }\n return api as unknown as RustrakClient;\n}\n\ntype Outcome = {\n data?: unknown;\n error?: unknown;\n response?: Response;\n};\n\n/**\n * The boundary: the generated client's `{ data, error, response }` becomes a\n * `Result`.\n *\n * Only failures this file recognises become an `Err`. Anything else, a\n * `TypeError` from a genuine bug, is rethrown so it crashes where it can be\n * debugged instead of being laundered into `{ success: false }`.\n */\nfunction toResult({\n data,\n error,\n response,\n}: Outcome): Result<unknown, RustrakError> {\n if (error === undefined) return Ok(data);\n if (isTransportFailure(error)) return Err(error.rustrakError);\n if (response && !response.ok) {\n // `error` is the parsed body, or its text when it is not JSON.\n return Err(transformHttpError(response, error));\n }\n if (!response && error instanceof ZodError) {\n return Err({\n kind: 'invalid_request',\n message: 'The request input did not match the expected schema.',\n });\n }\n if (response && error instanceof SyntaxError) {\n return Err({\n kind: 'invalid_response',\n message: 'The server returned a body that is not valid JSON.',\n });\n }\n if (response && error instanceof ZodError) {\n // No Zod issues: they embed the offending response data.\n return Err({\n kind: 'invalid_response',\n message: 'The server response did not match the expected schema.',\n });\n }\n throw error;\n}\n"],"mappings":";;;;;;;AAiBA,MAAM,yBAA8B,IAAI,IAAY,CAClD,2BACF,CAAC;;;;;;;;;;;;;;;;AAmDD,MAAa,gBAAgB,MAAM;CACjC,YAAY,QAAsB;EAEhC,OAAO,OAAO,eAAe,UAAU,MAAM,GAAG,WAAW,SAAS;CACtE;AACF;AAIA,SAAS,UAAU,QAAqC;CACtD,MAAM,MAAM,IAAI,QAAQ,EACtB,QAAQ,aACN,aAAa;EACX,SAAS,OAAO;EAChB,aAAa;EACb,OAAO,YAAY,MAAM;EAIzB,SAAS;EACT,SAAS;GAEP,QAAQ;GACR,GAAG,OAAO;GACV,GAAI,OAAO,SAAS,EAAE,eAAe,UAAU,OAAO,QAAQ;EAChE;CACF,CAAC,CACH,EACF,CAAC;CAED,MAAM,MAA+C,CAAC;CACtD,KAAK,MAAM,QAAQ,OAAO,oBAAoB,QAAQ,SAAS,GAAG;EAChE,IAAI,SAAS,eAAe;EAC5B,MAAM,WAAW,IAAI;EAIrB,MAAM,UAAmC,CAAC;EAC1C,KAAK,MAAM,UAAU,OAAO,oBAC1B,OAAO,eAAe,QAAQ,CAChC,GAAG;GACD,IAAI,WAAW,eAAe;GAC9B,QAAQ,UAAU,OAAO,UAAiC,CAAC,MACzD,SACE,MAAM,SAAS,OAAO,CAAE;IACtB,GAAG;IAGH,SACE,QAAQ,mBAAmB,WAC3B,MAAM,QAAQ,QAAQ,OAAO,IACzB,OAAO,YAAY,IAAI,QAAQ,QAAQ,OAAO,CAAC,IAC/C,QAAQ;IACd,GAAI,OAAO,IAAI,GAAG,KAAK,GAAG,QAAQ,KAAK,EAAE,SAAS,OAAO;IACzD,cAAc;GAChB,CAAC,CACH;EACJ;EACA,IAAI,QAAQ;CACd;CACA,OAAO;AACT;;;;;;;;;AAgBA,SAAS,SAAS,EAChB,MACA,OACA,YACyC;CACzC,IAAI,UAAU,KAAA,GAAW,OAAO,GAAG,IAAI;CACvC,IAAI,mBAAmB,KAAK,GAAG,OAAO,IAAI,MAAM,YAAY;CAC5D,IAAI,YAAY,CAAC,SAAS,IAExB,OAAO,IAAI,mBAAmB,UAAU,KAAK,CAAC;CAEhD,IAAI,CAAC,YAAY,iBAAiB,UAChC,OAAO,IAAI;EACT,MAAM;EACN,SAAS;CACX,CAAC;CAEH,IAAI,YAAY,iBAAiB,aAC/B,OAAO,IAAI;EACT,MAAM;EACN,SAAS;CACX,CAAC;CAEH,IAAI,YAAY,iBAAiB,UAE/B,OAAO,IAAI;EACT,MAAM;EACN,SAAS;CACX,CAAC;CAEH,MAAM;AACR"}
@@ -23,6 +23,225 @@ var HeyApiRegistry = class {
23
23
  this.instances.set(key ?? this.defaultKey, value);
24
24
  }
25
25
  };
26
+ var Sentry = class extends HeyApiClient {
27
+ /**
28
+ * GET /api/0/issues/{issue_id}/
29
+ *
30
+ * One issue with its releases and its 24h and 30d series (Sentry's
31
+ * `GroupDetailsEndpoint`). Also served under `/groups/` and the
32
+ * organization-scoped paths, as Sentry does.
33
+ */
34
+ getIssue(options) {
35
+ return (options.client ?? this.client).get({
36
+ requestValidator: async (data) => await zod.object({
37
+ body: zod.never().optional(),
38
+ path: require_zod_gen.zSentryGetIssuePath,
39
+ query: zod.never().optional()
40
+ }).parseAsync(data),
41
+ responseValidator: async (data) => await require_zod_gen.zSentryGetIssueResponse.parseAsync(data),
42
+ security: [{
43
+ scheme: "bearer",
44
+ type: "http"
45
+ }],
46
+ url: "/api/0/issues/{issue_id}/",
47
+ ...options
48
+ });
49
+ }
50
+ /**
51
+ * PUT /api/0/issues/{issue_id}/
52
+ *
53
+ * Sets an issue's status and returns the issue (Sentry's
54
+ * `GroupDetailsEndpoint.put`). The change goes through Rustrak's own
55
+ * issue update, so it is recorded and mirrored like any other.
56
+ */
57
+ updateIssue(options) {
58
+ return (options.client ?? this.client).put({
59
+ requestValidator: async (data) => await zod.object({
60
+ body: require_zod_gen.zSentryUpdateIssueBody,
61
+ path: require_zod_gen.zSentryUpdateIssuePath,
62
+ query: zod.never().optional()
63
+ }).parseAsync(data),
64
+ responseValidator: async (data) => await require_zod_gen.zSentryUpdateIssueResponse.parseAsync(data),
65
+ security: [{
66
+ scheme: "bearer",
67
+ type: "http"
68
+ }],
69
+ url: "/api/0/issues/{issue_id}/",
70
+ ...options,
71
+ headers: {
72
+ "Content-Type": "application/json",
73
+ ...options.headers
74
+ }
75
+ });
76
+ }
77
+ /**
78
+ * GET /api/0/issues/{issue_id}/events/latest/
79
+ *
80
+ * The issue's most recent event (Sentry's `GroupEventDetailsEndpoint`,
81
+ * `issues/endpoints/group_event_details.py`).
82
+ */
83
+ getLatestEvent(options) {
84
+ return (options.client ?? this.client).get({
85
+ requestValidator: async (data) => await zod.object({
86
+ body: zod.never().optional(),
87
+ path: require_zod_gen.zSentryGetLatestEventPath,
88
+ query: zod.never().optional()
89
+ }).parseAsync(data),
90
+ responseValidator: async (data) => await require_zod_gen.zSentryGetLatestEventResponse.parseAsync(data),
91
+ security: [{
92
+ scheme: "bearer",
93
+ type: "http"
94
+ }],
95
+ url: "/api/0/issues/{issue_id}/events/latest/",
96
+ ...options
97
+ });
98
+ }
99
+ /**
100
+ * GET /api/0/organizations/
101
+ *
102
+ * The organizations the token belongs to (Sentry's
103
+ * `OrganizationIndexEndpoint`): always the one synthetic org.
104
+ */
105
+ listOrganizations(options) {
106
+ return (options?.client ?? this.client).get({
107
+ requestValidator: async (data) => await zod.object({
108
+ body: zod.never().optional(),
109
+ path: zod.never().optional(),
110
+ query: zod.never().optional()
111
+ }).parseAsync(data),
112
+ responseValidator: async (data) => await require_zod_gen.zSentryListOrganizationsResponse.parseAsync(data),
113
+ security: [{
114
+ scheme: "bearer",
115
+ type: "http"
116
+ }],
117
+ url: "/api/0/organizations/",
118
+ ...options
119
+ });
120
+ }
121
+ /**
122
+ * GET /api/0/organizations/{org_slug}/repos/
123
+ *
124
+ * The code repositories connected to the organization (Sentry's
125
+ * `OrganizationRepositoriesEndpoint`). Rustrak connects none through
126
+ * Sentry's integrations, so the list is always empty.
127
+ */
128
+ listRepos(options) {
129
+ return (options.client ?? this.client).get({
130
+ requestValidator: async (data) => await zod.object({
131
+ body: zod.never().optional(),
132
+ path: require_zod_gen.zSentryListReposPath,
133
+ query: zod.never().optional()
134
+ }).parseAsync(data),
135
+ responseValidator: async (data) => await require_zod_gen.zSentryListReposResponse.parseAsync(data),
136
+ security: [{
137
+ scheme: "bearer",
138
+ type: "http"
139
+ }],
140
+ url: "/api/0/organizations/{org_slug}/repos/",
141
+ ...options
142
+ });
143
+ }
144
+ /**
145
+ * GET /api/0/projects/
146
+ *
147
+ * The projects the token can see, newest first (Sentry's
148
+ * `ProjectIndexEndpoint`, `core/endpoints/project_index.py`).
149
+ */
150
+ listProjects(options) {
151
+ return (options?.client ?? this.client).get({
152
+ requestValidator: async (data) => await zod.object({
153
+ body: zod.never().optional(),
154
+ path: zod.never().optional(),
155
+ query: require_zod_gen.zSentryListProjectsQuery.optional()
156
+ }).parseAsync(data),
157
+ responseValidator: async (data) => await require_zod_gen.zSentryListProjectsResponse.parseAsync(data),
158
+ security: [{
159
+ scheme: "bearer",
160
+ type: "http"
161
+ }],
162
+ url: "/api/0/projects/",
163
+ ...options
164
+ });
165
+ }
166
+ /**
167
+ * GET /api/0/projects/{org_slug}/{project_slug}/issues/
168
+ *
169
+ * A project's issues, filtered by `query`, sorted by `sort` and paginated
170
+ * by `cursor` (Sentry's `ProjectGroupIndexEndpoint`,
171
+ * `issues/endpoints/project_group_index.py`).
172
+ */
173
+ listIssues(options) {
174
+ return (options.client ?? this.client).get({
175
+ requestValidator: async (data) => await zod.object({
176
+ body: zod.never().optional(),
177
+ path: require_zod_gen.zSentryListIssuesPath,
178
+ query: require_zod_gen.zSentryListIssuesQuery.optional()
179
+ }).parseAsync(data),
180
+ responseValidator: async (data) => await require_zod_gen.zSentryListIssuesResponse.parseAsync(data),
181
+ security: [{
182
+ scheme: "bearer",
183
+ type: "http"
184
+ }],
185
+ url: "/api/0/projects/{org_slug}/{project_slug}/issues/",
186
+ ...options
187
+ });
188
+ }
189
+ /**
190
+ * POST /api/0/projects/{org_slug}/{project_slug}/user-feedback/
191
+ *
192
+ * Submit a user report about an error event (Sentry's
193
+ * `ProjectUserReportsEndpoint`, `feedback/endpoints/project_user_reports.py`).
194
+ * Accepts `Authorization: DSN <dsn>` as well as a token; the report becomes a
195
+ * feedback, as the `user_report` envelope item does.
196
+ */
197
+ submitUserFeedback(options) {
198
+ return (options.client ?? this.client).post({
199
+ requestValidator: async (data) => await zod.object({
200
+ body: require_zod_gen.zSentrySubmitUserFeedbackBody,
201
+ path: require_zod_gen.zSentrySubmitUserFeedbackPath,
202
+ query: zod.never().optional()
203
+ }).parseAsync(data),
204
+ responseValidator: async (data) => await require_zod_gen.zSentrySubmitUserFeedbackResponse.parseAsync(data),
205
+ security: [{
206
+ scheme: "bearer",
207
+ type: "http"
208
+ }],
209
+ url: "/api/0/projects/{org_slug}/{project_slug}/user-feedback/",
210
+ ...options,
211
+ headers: {
212
+ "Content-Type": "application/json",
213
+ ...options.headers
214
+ }
215
+ });
216
+ }
217
+ /**
218
+ * GET /{org_slug}/{project_slug}/issues/{issue_id}/
219
+ *
220
+ * The issue page GitLab's "View in Sentry" opens: Sentry redirects this
221
+ * legacy path to the issue (`static/app/router/routes.tsx`), Rustrak to its
222
+ * dashboard. A visitor who is not signed in goes to the login page instead,
223
+ * so a stranger learns nothing about which issues exist.
224
+ */
225
+ openIssue(options) {
226
+ return (options.client ?? this.client).get({
227
+ requestValidator: async (data) => await zod.object({
228
+ body: zod.never().optional(),
229
+ path: require_zod_gen.zSentryOpenIssuePath,
230
+ query: zod.never().optional()
231
+ }).parseAsync(data),
232
+ security: [{
233
+ in: "cookie",
234
+ name: "session",
235
+ type: "apiKey"
236
+ }, {
237
+ scheme: "bearer",
238
+ type: "http"
239
+ }],
240
+ url: "/{org_slug}/{project_slug}/issues/{issue_id}",
241
+ ...options
242
+ });
243
+ }
244
+ };
26
245
  var SourceMaps = class extends HeyApiClient {
27
246
  /**
28
247
  * GET /api/0/organizations/{org_slug}/
@@ -1297,6 +1516,27 @@ var AlertRules = class extends HeyApiClient {
1297
1516
  }
1298
1517
  };
1299
1518
  var Events = class extends HeyApiClient {
1519
+ /**
1520
+ * GET /api/projects/{project_id}/attachments/{attachment_id}
1521
+ * Downloads an attachment. Only a real image is served inline; anything
1522
+ * else, whatever type it claims, is a download that never runs.
1523
+ */
1524
+ downloadAttachment(options) {
1525
+ return (options.client ?? this.client).get({
1526
+ requestValidator: async (data) => await zod.object({
1527
+ body: zod.never().optional(),
1528
+ path: require_zod_gen.zEventsDownloadAttachmentPath,
1529
+ query: zod.never().optional()
1530
+ }).parseAsync(data),
1531
+ responseValidator: async (data) => await require_zod_gen.zEventsDownloadAttachmentResponse.parseAsync(data),
1532
+ security: [{
1533
+ scheme: "bearer",
1534
+ type: "http"
1535
+ }],
1536
+ url: "/api/projects/{project_id}/attachments/{attachment_id}",
1537
+ ...options
1538
+ });
1539
+ }
1300
1540
  /**
1301
1541
  * Resolve the ID returned by a Sentry SDK without already knowing the issue.
1302
1542
  */
@@ -1356,6 +1596,26 @@ var Events = class extends HeyApiClient {
1356
1596
  ...options
1357
1597
  });
1358
1598
  }
1599
+ /**
1600
+ * GET /api/projects/{project_id}/issues/{issue_id}/events/{event_id}/attachments
1601
+ * Lists the files sent with an event, such as a feedback's screenshot.
1602
+ */
1603
+ listAttachments(options) {
1604
+ return (options.client ?? this.client).get({
1605
+ requestValidator: async (data) => await zod.object({
1606
+ body: zod.never().optional(),
1607
+ path: require_zod_gen.zEventsListAttachmentsPath,
1608
+ query: zod.never().optional()
1609
+ }).parseAsync(data),
1610
+ responseValidator: async (data) => await require_zod_gen.zEventsListAttachmentsResponse.parseAsync(data),
1611
+ security: [{
1612
+ scheme: "bearer",
1613
+ type: "http"
1614
+ }],
1615
+ url: "/api/projects/{project_id}/issues/{issue_id}/events/{event_id}/attachments",
1616
+ ...options
1617
+ });
1618
+ }
1359
1619
  };
1360
1620
  var Stats = class extends HeyApiClient {
1361
1621
  /**
@@ -1397,6 +1657,29 @@ var Stats = class extends HeyApiClient {
1397
1657
  });
1398
1658
  }
1399
1659
  };
1660
+ var Feedback = class extends HeyApiClient {
1661
+ /**
1662
+ * GET /api/projects/{project_id}/feedback
1663
+ * Lists user feedback with what each user submitted. Every feedback is an
1664
+ * issue of category `feedback`; spam is a muted one.
1665
+ */
1666
+ list(options) {
1667
+ return (options.client ?? this.client).get({
1668
+ requestValidator: async (data) => await zod.object({
1669
+ body: zod.never().optional(),
1670
+ path: require_zod_gen.zFeedbackListPath,
1671
+ query: require_zod_gen.zFeedbackListQuery.optional()
1672
+ }).parseAsync(data),
1673
+ responseValidator: async (data) => await require_zod_gen.zFeedbackListResponse.parseAsync(data),
1674
+ security: [{
1675
+ scheme: "bearer",
1676
+ type: "http"
1677
+ }],
1678
+ url: "/api/projects/{project_id}/feedback",
1679
+ ...options
1680
+ });
1681
+ }
1682
+ };
1400
1683
  var Issues = class extends HeyApiClient {
1401
1684
  /**
1402
1685
  * DELETE /api/projects/{project_id}/issues (bulk delete by ids or filter)
@@ -1722,7 +2005,7 @@ var Issues = class extends HeyApiClient {
1722
2005
  requestValidator: async (data) => await zod.object({
1723
2006
  body: zod.never().optional(),
1724
2007
  path: require_zod_gen.zIssuesListUserReportsPath,
1725
- query: zod.never().optional()
2008
+ query: require_zod_gen.zIssuesListUserReportsQuery.optional()
1726
2009
  }).parseAsync(data),
1727
2010
  responseValidator: async (data) => await require_zod_gen.zIssuesListUserReportsResponse.parseAsync(data),
1728
2011
  security: [{
@@ -3001,6 +3284,10 @@ var Rustrak = class Rustrak extends HeyApiClient {
3001
3284
  super(args);
3002
3285
  Rustrak.__registry.set(this, args?.key);
3003
3286
  }
3287
+ _sentry;
3288
+ get sentry() {
3289
+ return this._sentry ??= new Sentry({ client: this.client });
3290
+ }
3004
3291
  _sourceMaps;
3005
3292
  get sourceMaps() {
3006
3293
  return this._sourceMaps ??= new SourceMaps({ client: this.client });
@@ -3045,6 +3332,10 @@ var Rustrak = class Rustrak extends HeyApiClient {
3045
3332
  get stats() {
3046
3333
  return this._stats ??= new Stats({ client: this.client });
3047
3334
  }
3335
+ _feedback;
3336
+ get feedback() {
3337
+ return this._feedback ??= new Feedback({ client: this.client });
3338
+ }
3048
3339
  _issues;
3049
3340
  get issues() {
3050
3341
  return this._issues ??= new Issues({ client: this.client });
@@ -3112,6 +3403,7 @@ exports.AlertChannels = AlertChannels;
3112
3403
  exports.AlertRules = AlertRules;
3113
3404
  exports.Auth = Auth;
3114
3405
  exports.Events = Events;
3406
+ exports.Feedback = Feedback;
3115
3407
  exports.Github = Github;
3116
3408
  exports.Health = Health;
3117
3409
  exports.Invitations = Invitations;
@@ -3124,6 +3416,7 @@ exports.Projects = Projects;
3124
3416
  exports.Releases = Releases;
3125
3417
  exports.Rustrak = Rustrak;
3126
3418
  exports.Schedules = Schedules;
3419
+ exports.Sentry = Sentry;
3127
3420
  exports.Sessions = Sessions;
3128
3421
  exports.Settings = Settings;
3129
3422
  exports.SourceMaps = SourceMaps;