bitbucket-datacenter-api-client 1.1.0 → 1.2.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 +208 -0
- package/dist/index.d.mts +492 -13
- package/dist/index.d.ts +492 -13
- package/dist/index.js +235 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +235 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -24,7 +24,8 @@ __export(index_exports, {
|
|
|
24
24
|
ProjectResource: () => ProjectResource,
|
|
25
25
|
PullRequestResource: () => PullRequestResource,
|
|
26
26
|
RepositoryResource: () => RepositoryResource,
|
|
27
|
-
Security: () => Security
|
|
27
|
+
Security: () => Security,
|
|
28
|
+
UserResource: () => UserResource
|
|
28
29
|
});
|
|
29
30
|
module.exports = __toCommonJS(index_exports);
|
|
30
31
|
|
|
@@ -124,13 +125,99 @@ var PullRequestResource = class {
|
|
|
124
125
|
);
|
|
125
126
|
return data.values;
|
|
126
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Fetches the tasks (review to-do items) for this pull request.
|
|
130
|
+
*
|
|
131
|
+
* Tasks are created by reviewers on specific comments and can be `OPEN` or `RESOLVED`.
|
|
132
|
+
*
|
|
133
|
+
* `GET /rest/api/latest/projects/{key}/repos/{slug}/pull-requests/{id}/tasks`
|
|
134
|
+
*
|
|
135
|
+
* @param params - Optional filters: `limit`, `start`
|
|
136
|
+
* @returns An array of pull request tasks
|
|
137
|
+
*/
|
|
138
|
+
async tasks(params) {
|
|
139
|
+
const data = await this.request(
|
|
140
|
+
`${this.basePath}/tasks`,
|
|
141
|
+
params
|
|
142
|
+
);
|
|
143
|
+
return data.values;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Fetches the commits included in this pull request.
|
|
147
|
+
*
|
|
148
|
+
* `GET /rest/api/latest/projects/{key}/repos/{slug}/pull-requests/{id}/commits`
|
|
149
|
+
*
|
|
150
|
+
* @param params - Optional pagination: `limit`, `start`
|
|
151
|
+
* @returns An array of commits
|
|
152
|
+
*/
|
|
153
|
+
async commits(params) {
|
|
154
|
+
const data = await this.request(
|
|
155
|
+
`${this.basePath}/commits`,
|
|
156
|
+
params
|
|
157
|
+
);
|
|
158
|
+
return data.values;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Fetches the file changes included in this pull request.
|
|
162
|
+
*
|
|
163
|
+
* `GET /rest/api/latest/projects/{key}/repos/{slug}/pull-requests/{id}/changes`
|
|
164
|
+
*
|
|
165
|
+
* @param params - Optional filters: `limit`, `start`, `withComments`
|
|
166
|
+
* @returns An array of file changes
|
|
167
|
+
*/
|
|
168
|
+
async changes(params) {
|
|
169
|
+
const data = await this.request(
|
|
170
|
+
`${this.basePath}/changes`,
|
|
171
|
+
params
|
|
172
|
+
);
|
|
173
|
+
return data.values;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Fetches the Code Insights reports for this pull request.
|
|
177
|
+
*
|
|
178
|
+
* `GET /rest/api/latest/projects/{key}/repos/{slug}/pull-requests/{id}/reports`
|
|
179
|
+
*
|
|
180
|
+
* @param params - Optional pagination: `limit`, `start`
|
|
181
|
+
* @returns An array of Code Insights reports
|
|
182
|
+
*/
|
|
183
|
+
async reports(params) {
|
|
184
|
+
const data = await this.request(
|
|
185
|
+
`${this.basePath}/reports`,
|
|
186
|
+
params
|
|
187
|
+
);
|
|
188
|
+
return data.values;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Fetches the aggregated build summaries for this pull request.
|
|
192
|
+
*
|
|
193
|
+
* Returns a map of commit hash → build counts per state
|
|
194
|
+
* (`successful`, `failed`, `inProgress`, `cancelled`, `unknown`).
|
|
195
|
+
*
|
|
196
|
+
* `GET /rest/api/latest/projects/{key}/repos/{slug}/pull-requests/{id}/build-summaries`
|
|
197
|
+
*
|
|
198
|
+
* @returns A record keyed by commit SHA with aggregated build counts
|
|
199
|
+
*/
|
|
200
|
+
async buildSummaries() {
|
|
201
|
+
return this.request(`${this.basePath}/build-summaries`);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Fetches the Jira issues linked to this pull request.
|
|
205
|
+
*
|
|
206
|
+
* `GET /rest/api/latest/projects/{key}/repos/{slug}/pull-requests/{id}/issues`
|
|
207
|
+
*
|
|
208
|
+
* @returns An array of linked Jira issues
|
|
209
|
+
*/
|
|
210
|
+
async issues() {
|
|
211
|
+
return this.request(`${this.basePath}/issues`);
|
|
212
|
+
}
|
|
127
213
|
};
|
|
128
214
|
|
|
129
215
|
// src/resources/RepositoryResource.ts
|
|
130
216
|
var RepositoryResource = class {
|
|
131
217
|
/** @internal */
|
|
132
|
-
constructor(request, projectKey, repoSlug) {
|
|
218
|
+
constructor(request, requestText, projectKey, repoSlug) {
|
|
133
219
|
this.request = request;
|
|
220
|
+
this.requestText = requestText;
|
|
134
221
|
this.projectKey = projectKey;
|
|
135
222
|
this.repoSlug = repoSlug;
|
|
136
223
|
this.basePath = `/projects/${projectKey}/repos/${repoSlug}`;
|
|
@@ -182,6 +269,46 @@ var RepositoryResource = class {
|
|
|
182
269
|
);
|
|
183
270
|
return data.values;
|
|
184
271
|
}
|
|
272
|
+
/**
|
|
273
|
+
* Fetches the files last modified in this repository along with the commit that last touched each.
|
|
274
|
+
*
|
|
275
|
+
* `GET /rest/api/latest/projects/{key}/repos/{slug}/last-modified`
|
|
276
|
+
*
|
|
277
|
+
* @param params - Optional filters: `limit`, `start`, `at`
|
|
278
|
+
* @returns An array of last-modified entries
|
|
279
|
+
*/
|
|
280
|
+
async lastModified(params) {
|
|
281
|
+
const data = await this.request(
|
|
282
|
+
`${this.basePath}/last-modified`,
|
|
283
|
+
params
|
|
284
|
+
);
|
|
285
|
+
return data.values;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Fetches the size of this repository.
|
|
289
|
+
*
|
|
290
|
+
* `GET /rest/api/latest/projects/{key}/repos/{slug}/sizes`
|
|
291
|
+
*
|
|
292
|
+
* @returns The repository size object
|
|
293
|
+
*/
|
|
294
|
+
async size() {
|
|
295
|
+
return this.request(`${this.basePath}/sizes`);
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Fetches branches for this repository.
|
|
299
|
+
*
|
|
300
|
+
* `GET /rest/api/latest/projects/{key}/repos/{slug}/branches`
|
|
301
|
+
*
|
|
302
|
+
* @param params - Optional filters: `limit`, `start`, `filterText`, `orderBy`, `details`, `base`, `boostMatches`
|
|
303
|
+
* @returns An array of branches
|
|
304
|
+
*/
|
|
305
|
+
async branches(params) {
|
|
306
|
+
const data = await this.request(
|
|
307
|
+
`${this.basePath}/branches`,
|
|
308
|
+
params
|
|
309
|
+
);
|
|
310
|
+
return data.values;
|
|
311
|
+
}
|
|
185
312
|
/**
|
|
186
313
|
* Returns a {@link PullRequestResource} for a given pull request ID, providing
|
|
187
314
|
* access to pull request data and sub-resources (activities, etc.).
|
|
@@ -198,6 +325,21 @@ var RepositoryResource = class {
|
|
|
198
325
|
* const activities = await bbClient.project('PROJ').repo('my-repo').pullRequest(42).activities();
|
|
199
326
|
* ```
|
|
200
327
|
*/
|
|
328
|
+
/**
|
|
329
|
+
* Fetches the raw content of a file in this repository.
|
|
330
|
+
*
|
|
331
|
+
* `GET /rest/api/latest/projects/{key}/repos/{slug}/raw/{path}`
|
|
332
|
+
*
|
|
333
|
+
* @param filePath - Path to the file (e.g., `'src/index.ts'`)
|
|
334
|
+
* @param params - Optional: `at` (branch, tag, or commit SHA)
|
|
335
|
+
* @returns The raw file content as a string
|
|
336
|
+
*/
|
|
337
|
+
async raw(filePath, params) {
|
|
338
|
+
return this.requestText(
|
|
339
|
+
`${this.basePath}/raw/${filePath}`,
|
|
340
|
+
params
|
|
341
|
+
);
|
|
342
|
+
}
|
|
201
343
|
pullRequest(pullRequestId) {
|
|
202
344
|
return new PullRequestResource(this.request, this.projectKey, this.repoSlug, pullRequestId);
|
|
203
345
|
}
|
|
@@ -206,8 +348,9 @@ var RepositoryResource = class {
|
|
|
206
348
|
// src/resources/ProjectResource.ts
|
|
207
349
|
var ProjectResource = class {
|
|
208
350
|
/** @internal */
|
|
209
|
-
constructor(request, key) {
|
|
351
|
+
constructor(request, requestText, key) {
|
|
210
352
|
this.request = request;
|
|
353
|
+
this.requestText = requestText;
|
|
211
354
|
this.key = key;
|
|
212
355
|
}
|
|
213
356
|
/**
|
|
@@ -260,7 +403,48 @@ var ProjectResource = class {
|
|
|
260
403
|
* ```
|
|
261
404
|
*/
|
|
262
405
|
repo(repoSlug) {
|
|
263
|
-
return new RepositoryResource(this.request, this.key, repoSlug);
|
|
406
|
+
return new RepositoryResource(this.request, this.requestText, this.key, repoSlug);
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Fetches users with explicit permissions on this project.
|
|
410
|
+
*
|
|
411
|
+
* `GET /rest/api/latest/projects/{key}/permissions/users`
|
|
412
|
+
*
|
|
413
|
+
* @param params - Optional filters: `limit`, `start`, `filter`, `permission`
|
|
414
|
+
* @returns An array of user–permission pairs
|
|
415
|
+
*/
|
|
416
|
+
async users(params) {
|
|
417
|
+
const data = await this.request(
|
|
418
|
+
`/projects/${this.key}/permissions/users`,
|
|
419
|
+
params
|
|
420
|
+
);
|
|
421
|
+
return data.values;
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
// src/resources/UserResource.ts
|
|
426
|
+
var UserResource = class {
|
|
427
|
+
/** @internal */
|
|
428
|
+
constructor(request, slug) {
|
|
429
|
+
this.request = request;
|
|
430
|
+
this.basePath = `/users/${slug}`;
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Allows the resource to be awaited directly, resolving with the user info.
|
|
434
|
+
* Delegates to {@link UserResource.get}.
|
|
435
|
+
*/
|
|
436
|
+
then(onfulfilled, onrejected) {
|
|
437
|
+
return this.get().then(onfulfilled, onrejected);
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Fetches the user details.
|
|
441
|
+
*
|
|
442
|
+
* `GET /rest/api/latest/users/{slug}`
|
|
443
|
+
*
|
|
444
|
+
* @returns The user object
|
|
445
|
+
*/
|
|
446
|
+
async get() {
|
|
447
|
+
return this.request(this.basePath);
|
|
264
448
|
}
|
|
265
449
|
};
|
|
266
450
|
|
|
@@ -270,8 +454,9 @@ var BitbucketClient = class {
|
|
|
270
454
|
* @param options - Connection and authentication options
|
|
271
455
|
* @throws {TypeError} If `apiUrl` is not a valid URL
|
|
272
456
|
*/
|
|
273
|
-
constructor({ apiUrl, user, token }) {
|
|
457
|
+
constructor({ apiUrl, apiPath, user, token }) {
|
|
274
458
|
this.security = new Security(apiUrl, user, token);
|
|
459
|
+
this.apiPath = apiPath.replace(/^\/|\/$/g, "");
|
|
275
460
|
}
|
|
276
461
|
/**
|
|
277
462
|
* Performs an authenticated GET request to the Bitbucket REST API.
|
|
@@ -282,7 +467,7 @@ var BitbucketClient = class {
|
|
|
282
467
|
* @internal
|
|
283
468
|
*/
|
|
284
469
|
async request(path, params) {
|
|
285
|
-
const base = `${this.security.getApiUrl()}${path}`;
|
|
470
|
+
const base = `${this.security.getApiUrl()}/${this.apiPath}${path}`;
|
|
286
471
|
const url = buildUrl(base, params);
|
|
287
472
|
const response = await fetch(url, { headers: this.security.getHeaders() });
|
|
288
473
|
if (!response.ok) {
|
|
@@ -290,6 +475,15 @@ var BitbucketClient = class {
|
|
|
290
475
|
}
|
|
291
476
|
return response.json();
|
|
292
477
|
}
|
|
478
|
+
async requestText(path, params) {
|
|
479
|
+
const base = `${this.security.getApiUrl()}/${this.apiPath}${path}`;
|
|
480
|
+
const url = buildUrl(base, params);
|
|
481
|
+
const response = await fetch(url, { headers: this.security.getHeaders() });
|
|
482
|
+
if (!response.ok) {
|
|
483
|
+
throw new Error(`Bitbucket API error: ${response.status} ${response.statusText}`);
|
|
484
|
+
}
|
|
485
|
+
return response.text();
|
|
486
|
+
}
|
|
293
487
|
/**
|
|
294
488
|
* Fetches all projects accessible to the authenticated user.
|
|
295
489
|
*
|
|
@@ -324,7 +518,41 @@ var BitbucketClient = class {
|
|
|
324
518
|
*/
|
|
325
519
|
project(projectKey) {
|
|
326
520
|
const request = (path, params) => this.request(path, params);
|
|
327
|
-
|
|
521
|
+
const requestText = (path, params) => this.requestText(path, params);
|
|
522
|
+
return new ProjectResource(request, requestText, projectKey);
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Fetches all users accessible to the authenticated user.
|
|
526
|
+
*
|
|
527
|
+
* `GET /rest/api/latest/users`
|
|
528
|
+
*
|
|
529
|
+
* @param params - Optional filters: `limit`, `start`, `filter`
|
|
530
|
+
* @returns An array of users
|
|
531
|
+
*/
|
|
532
|
+
async users(params) {
|
|
533
|
+
const data = await this.request(
|
|
534
|
+
"/users",
|
|
535
|
+
params
|
|
536
|
+
);
|
|
537
|
+
return data.values;
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Returns a {@link UserResource} for a given user slug, providing access
|
|
541
|
+
* to user data.
|
|
542
|
+
*
|
|
543
|
+
* The returned resource can be awaited directly to fetch user info.
|
|
544
|
+
*
|
|
545
|
+
* @param slug - The user slug (e.g., `'pilmee'`)
|
|
546
|
+
* @returns A chainable user resource
|
|
547
|
+
*
|
|
548
|
+
* @example
|
|
549
|
+
* ```typescript
|
|
550
|
+
* const user = await bbClient.user('pilmee');
|
|
551
|
+
* ```
|
|
552
|
+
*/
|
|
553
|
+
user(slug) {
|
|
554
|
+
const request = (path, params) => this.request(path, params);
|
|
555
|
+
return new UserResource(request, slug);
|
|
328
556
|
}
|
|
329
557
|
};
|
|
330
558
|
function buildUrl(base, params) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/security/Security.ts","../src/resources/PullRequestResource.ts","../src/resources/RepositoryResource.ts","../src/resources/ProjectResource.ts","../src/BitbucketClient.ts"],"sourcesContent":["export { BitbucketClient } from './BitbucketClient';\nexport type { BitbucketClientOptions } from './BitbucketClient';\nexport { Security } from './security/Security';\nexport { ProjectResource } from './resources/ProjectResource';\nexport { RepositoryResource } from './resources/RepositoryResource';\nexport { PullRequestResource } from './resources/PullRequestResource';\nexport type { BitbucketProject, ProjectsParams } from './domain/Project';\nexport type { BitbucketRepository, ReposParams } from './domain/Repository';\nexport type { BitbucketPullRequest, BitbucketParticipant, BitbucketRef, PullRequestsParams } from './domain/PullRequest';\nexport type { BitbucketPullRequestActivity, BitbucketPullRequestComment, BitbucketActivityUser, PullRequestActivityAction, ActivitiesParams } from './domain/PullRequestActivity';\nexport type { BitbucketCommit, BitbucketCommitAuthor, CommitsParams } from './domain/Commit';\nexport type { PaginationParams, PagedResponse } from './domain/Pagination';\n","/**\n * Encodes a string to Base64 in a way that works in both Node.js and browsers.\n * @internal\n */\nfunction toBase64(value: string): string {\n if (typeof btoa !== 'undefined') {\n return btoa(value);\n }\n return Buffer.from(value).toString('base64');\n}\n\n/**\n * Handles Basic Authentication for Bitbucket Data Center REST API requests.\n *\n * @example\n * ```typescript\n * const security = new Security(\n * 'https://bitbucket.example.com',\n * 'my-user',\n * 'my-token'\n * );\n *\n * const headers = security.getHeaders();\n * // { Authorization: 'Basic <base64>', 'Content-Type': 'application/json', Accept: 'application/json' }\n * ```\n */\nexport class Security {\n private readonly apiUrl: string;\n private readonly authorizationHeader: string;\n\n /**\n * Creates a new Security instance with Basic Authentication credentials.\n *\n * @param apiUrl - The base URL of the Bitbucket Data Center instance (e.g., `https://bitbucket.example.com`).\n * Must be a valid URL; throws if it cannot be parsed.\n * @param user - The username to authenticate with\n * @param token - The personal access token or password to authenticate with\n *\n * @throws {TypeError} If `apiUrl` is not a valid URL\n */\n constructor(apiUrl: string, user: string, token: string) {\n if (!URL.canParse(apiUrl)) {\n throw new TypeError(`Invalid apiUrl: \"${apiUrl}\" is not a valid URL`);\n }\n this.apiUrl = apiUrl.replace(/\\/$/, '');\n this.authorizationHeader = `Basic ${toBase64(`${user}:${token}`)}`;\n }\n\n /**\n * Returns the base URL of the Bitbucket Data Center instance, without a trailing slash.\n *\n * @returns The API base URL\n */\n getApiUrl(): string {\n return this.apiUrl;\n }\n\n /**\n * Returns the value of the `Authorization` header for Basic Authentication.\n *\n * @returns The Authorization header value in the format `Basic <base64-encoded-credentials>`\n */\n getAuthorizationHeader(): string {\n return this.authorizationHeader;\n }\n\n /**\n * Returns the full set of HTTP headers required for authenticated API requests.\n *\n * @returns An object containing `Authorization`, `Content-Type`, and `Accept` headers\n */\n getHeaders(): Record<string, string> {\n return {\n Authorization: this.authorizationHeader,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n };\n }\n}\n","import type { BitbucketPullRequest } from '../domain/PullRequest';\nimport type { BitbucketPullRequestActivity, ActivitiesParams } from '../domain/PullRequestActivity';\nimport type { PagedResponse } from '../domain/Pagination';\nimport type { RequestFn } from './ProjectResource';\n\n/**\n * Represents a Bitbucket pull request resource with chainable async methods.\n *\n * Implements `PromiseLike<BitbucketPullRequest>` so it can be awaited directly\n * to fetch the pull request info, while also exposing sub-resource methods.\n *\n * @example\n * ```typescript\n * // Await directly to get pull request info\n * const pr = await bbClient.project('PROJ').repo('my-repo').pullRequest(42);\n *\n * // Get activities\n * const activities = await bbClient.project('PROJ').repo('my-repo').pullRequest(42).activities();\n *\n * // With filters\n * const comments = await bbClient\n * .project('PROJ')\n * .repo('my-repo')\n * .pullRequest(42)\n * .activities({ fromId: 10, fromType: 'COMMENT' });\n * ```\n */\nexport class PullRequestResource implements PromiseLike<BitbucketPullRequest> {\n private readonly basePath: string;\n\n /** @internal */\n constructor(\n private readonly request: RequestFn,\n projectKey: string,\n repoSlug: string,\n pullRequestId: number,\n ) {\n this.basePath = `/projects/${projectKey}/repos/${repoSlug}/pull-requests/${pullRequestId}`;\n }\n\n /**\n * Allows the resource to be awaited directly, resolving with the pull request info.\n * Delegates to {@link PullRequestResource.get}.\n */\n then<TResult1 = BitbucketPullRequest, TResult2 = never>(\n onfulfilled?: ((value: BitbucketPullRequest) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): PromiseLike<TResult1 | TResult2> {\n return this.get().then(onfulfilled, onrejected);\n }\n\n /**\n * Fetches the pull request details.\n *\n * `GET /rest/api/latest/projects/{key}/repos/{slug}/pull-requests/{id}`\n *\n * @returns The pull request object\n */\n async get(): Promise<BitbucketPullRequest> {\n return this.request<BitbucketPullRequest>(this.basePath);\n }\n\n /**\n * Fetches the activity feed for this pull request.\n *\n * Activities include comments, approvals, reviews, rescopes, merges, and declines.\n *\n * `GET /rest/api/latest/projects/{key}/repos/{slug}/pull-requests/{id}/activities`\n *\n * @param params - Optional filters: `limit`, `start`, `fromId`, `fromType`\n * @returns An array of pull request activities, ordered from most recent to oldest\n */\n async activities(params?: ActivitiesParams): Promise<BitbucketPullRequestActivity[]> {\n const data = await this.request<PagedResponse<BitbucketPullRequestActivity>>(\n `${this.basePath}/activities`,\n params as Record<string, string | number | boolean>,\n );\n return data.values;\n }\n}\n","import type { BitbucketRepository } from '../domain/Repository';\nimport type { BitbucketPullRequest, PullRequestsParams } from '../domain/PullRequest';\nimport type { BitbucketCommit, CommitsParams } from '../domain/Commit';\nimport type { PagedResponse } from '../domain/Pagination';\nimport type { RequestFn } from './ProjectResource';\nimport { PullRequestResource } from './PullRequestResource';\n\n/**\n * Represents a Bitbucket repository resource with chainable async methods.\n *\n * Implements `PromiseLike<BitbucketRepository>` so it can be awaited directly\n * to fetch repository info, while also exposing sub-resource methods.\n *\n * @example\n * ```typescript\n * // Await directly to get repository info\n * const repo = await bbClient.project('PROJ').repo('my-repo');\n *\n * // Get pull requests\n * const prs = await bbClient.project('PROJ').repo('my-repo').pullRequests({ state: 'OPEN' });\n *\n * // Navigate into a specific pull request\n * const activities = await bbClient.project('PROJ').repo('my-repo').pullRequest(42).activities();\n *\n * // Get commits\n * const commits = await bbClient.project('PROJ').repo('my-repo').commits({ limit: 10 });\n * ```\n */\nexport class RepositoryResource implements PromiseLike<BitbucketRepository> {\n private readonly basePath: string;\n\n /** @internal */\n constructor(\n private readonly request: RequestFn,\n private readonly projectKey: string,\n private readonly repoSlug: string,\n ) {\n this.basePath = `/projects/${projectKey}/repos/${repoSlug}`;\n }\n\n /**\n * Allows the resource to be awaited directly, resolving with the repository info.\n * Delegates to {@link RepositoryResource.get}.\n */\n then<TResult1 = BitbucketRepository, TResult2 = never>(\n onfulfilled?: ((value: BitbucketRepository) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): PromiseLike<TResult1 | TResult2> {\n return this.get().then(onfulfilled, onrejected);\n }\n\n /**\n * Fetches the repository details.\n *\n * `GET /rest/api/latest/projects/{key}/repos/{slug}`\n *\n * @returns The repository object\n */\n async get(): Promise<BitbucketRepository> {\n return this.request<BitbucketRepository>(this.basePath);\n }\n\n /**\n * Fetches pull requests for this repository.\n *\n * `GET /rest/api/latest/projects/{key}/repos/{slug}/pull-requests`\n *\n * @param params - Optional filters: `limit`, `start`, `state`, `direction`, `at`, `order`\n * @returns An array of pull requests\n */\n async pullRequests(params?: PullRequestsParams): Promise<BitbucketPullRequest[]> {\n const data = await this.request<PagedResponse<BitbucketPullRequest>>(\n `${this.basePath}/pull-requests`,\n params as Record<string, string | number | boolean>,\n );\n return data.values;\n }\n\n /**\n * Fetches commits for this repository.\n *\n * `GET /rest/api/latest/projects/{key}/repos/{slug}/commits`\n *\n * @param params - Optional filters: `limit`, `start`, `until`, `since`, `path`, `merges`, `followRenames`, `ignoreMissing`\n * @returns An array of commits\n */\n async commits(params?: CommitsParams): Promise<BitbucketCommit[]> {\n const data = await this.request<PagedResponse<BitbucketCommit>>(\n `${this.basePath}/commits`,\n params as Record<string, string | number | boolean>,\n );\n return data.values;\n }\n\n /**\n * Returns a {@link PullRequestResource} for a given pull request ID, providing\n * access to pull request data and sub-resources (activities, etc.).\n *\n * The returned resource can be awaited directly to fetch pull request info,\n * or chained to access nested resources.\n *\n * @param pullRequestId - The numeric pull request ID\n * @returns A chainable pull request resource\n *\n * @example\n * ```typescript\n * const pr = await bbClient.project('PROJ').repo('my-repo').pullRequest(42);\n * const activities = await bbClient.project('PROJ').repo('my-repo').pullRequest(42).activities();\n * ```\n */\n pullRequest(pullRequestId: number): PullRequestResource {\n return new PullRequestResource(this.request, this.projectKey, this.repoSlug, pullRequestId);\n }\n}\n","import type { BitbucketProject } from '../domain/Project';\nimport type { BitbucketRepository, ReposParams } from '../domain/Repository';\nimport type { PagedResponse } from '../domain/Pagination';\nimport { RepositoryResource } from './RepositoryResource';\n\n/** @internal */\nexport type RequestFn = <T>(\n path: string,\n params?: Record<string, string | number | boolean>,\n) => Promise<T>;\n\n/**\n * Represents a Bitbucket project resource with chainable async methods.\n *\n * Implements `PromiseLike<BitbucketProject>` so it can be awaited directly\n * to fetch the project info, while also exposing sub-resource methods.\n *\n * @example\n * ```typescript\n * // Await directly to get project info\n * const project = await bbClient.project('PROJ');\n *\n * // Get repositories with filters\n * const repos = await bbClient.project('PROJ').repos({ limit: 50, name: 'api' });\n *\n * // Navigate into a specific repository\n * const prs = await bbClient.project('PROJ').repo('my-repo').pullRequests();\n * ```\n */\nexport class ProjectResource implements PromiseLike<BitbucketProject> {\n /** @internal */\n constructor(\n private readonly request: RequestFn,\n private readonly key: string,\n ) {}\n\n /**\n * Allows the resource to be awaited directly, resolving with the project info.\n * Delegates to {@link ProjectResource.get}.\n */\n then<TResult1 = BitbucketProject, TResult2 = never>(\n onfulfilled?: ((value: BitbucketProject) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): PromiseLike<TResult1 | TResult2> {\n return this.get().then(onfulfilled, onrejected);\n }\n\n /**\n * Fetches the project details.\n *\n * `GET /rest/api/latest/projects/{key}`\n *\n * @returns The project object\n */\n async get(): Promise<BitbucketProject> {\n return this.request<BitbucketProject>(`/projects/${this.key}`);\n }\n\n /**\n * Fetches repositories belonging to this project.\n *\n * `GET /rest/api/latest/projects/{key}/repos`\n *\n * @param params - Optional filters: `limit`, `start`, `slug`, `name`, `permission`\n * @returns An array of repositories\n */\n async repos(params?: ReposParams): Promise<BitbucketRepository[]> {\n const data = await this.request<PagedResponse<BitbucketRepository>>(\n `/projects/${this.key}/repos`,\n params as Record<string, string | number | boolean>,\n );\n return data.values;\n }\n\n /**\n * Returns a {@link RepositoryResource} for a given repository slug, providing\n * access to repository-level data and sub-resources (pull requests, commits, etc.).\n *\n * The returned resource can be awaited directly to fetch repository info,\n * or chained to access nested resources.\n *\n * @param repoSlug - The repository slug (e.g., `'my-repo'`)\n * @returns A chainable repository resource\n *\n * @example\n * ```typescript\n * const repo = await bbClient.project('PROJ').repo('my-repo');\n * const prs = await bbClient.project('PROJ').repo('my-repo').pullRequests({ state: 'OPEN' });\n * const commits = await bbClient.project('PROJ').repo('my-repo').commits({ limit: 10 });\n * ```\n */\n repo(repoSlug: string): RepositoryResource {\n return new RepositoryResource(this.request, this.key, repoSlug);\n }\n}\n","import { Security } from './security/Security';\nimport { ProjectResource, type RequestFn } from './resources/ProjectResource';\nimport type { BitbucketProject, ProjectsParams } from './domain/Project';\nimport type { PagedResponse } from './domain/Pagination';\n\n/**\n * Constructor options for {@link BitbucketClient}.\n */\nexport interface BitbucketClientOptions {\n /** The base URL of the Bitbucket Data Center instance (e.g., `https://bitbucket.example.com`) */\n apiUrl: string;\n /** The username to authenticate with */\n user: string;\n /** The personal access token or password to authenticate with */\n token: string;\n}\n\n/**\n * Main entry point for the Bitbucket Data Center REST API client.\n *\n * @example\n * ```typescript\n * const bbClient = new BitbucketClient({\n * apiUrl: 'https://bitbucket.example.com/rest/api/latest',\n * user: 'john.doe',\n * token: 'my-token',\n * });\n *\n * const projects = await bbClient.projects({ limit: 50 });\n * const project = await bbClient.project('PROJ');\n * const repos = await bbClient.project('PROJ').repos({ name: 'api' });\n * const repo = await bbClient.project('PROJ').repo('my-repo');\n * const prs = await bbClient.project('PROJ').repo('my-repo').pullRequests({ state: 'OPEN' });\n * const commits = await bbClient.project('PROJ').repo('my-repo').commits({ limit: 10 });\n * ```\n */\nexport class BitbucketClient {\n private readonly security: Security;\n\n /**\n * @param options - Connection and authentication options\n * @throws {TypeError} If `apiUrl` is not a valid URL\n */\n constructor({ apiUrl, user, token }: BitbucketClientOptions) {\n this.security = new Security(apiUrl, user, token);\n }\n\n /**\n * Performs an authenticated GET request to the Bitbucket REST API.\n *\n * @param path - API path appended directly to `apiUrl` (e.g., `'/projects'`)\n * @param params - Optional query parameters to append to the URL\n * @throws {Error} If the HTTP response is not OK\n * @internal\n */\n private async request<T>(\n path: string,\n params?: Record<string, string | number | boolean>,\n ): Promise<T> {\n const base = `${this.security.getApiUrl()}${path}`;\n const url = buildUrl(base, params);\n const response = await fetch(url, { headers: this.security.getHeaders() });\n if (!response.ok) {\n throw new Error(`Bitbucket API error: ${response.status} ${response.statusText}`);\n }\n return response.json() as Promise<T>;\n }\n\n /**\n * Fetches all projects accessible to the authenticated user.\n *\n * `GET /rest/api/latest/projects`\n *\n * @param params - Optional filters: `limit`, `start`, `name`, `permission`\n * @returns An array of projects\n */\n async projects(params?: ProjectsParams): Promise<BitbucketProject[]> {\n const data = await this.request<PagedResponse<BitbucketProject>>(\n '/projects',\n params as Record<string, string | number | boolean>,\n );\n return data.values;\n }\n\n /**\n * Returns a {@link ProjectResource} for a given project key, providing access\n * to project-level data and sub-resources.\n *\n * The returned resource can be awaited directly to fetch project info,\n * or chained to access nested resources.\n *\n * @param projectKey - The project key (e.g., `'PROJ'`)\n * @returns A chainable project resource\n *\n * @example\n * ```typescript\n * const project = await bbClient.project('PROJ');\n * const repos = await bbClient.project('PROJ').repos({ limit: 10 });\n * const prs = await bbClient.project('PROJ').repo('my-repo').pullRequests();\n * ```\n */\n project(projectKey: string): ProjectResource {\n const request: RequestFn = <T>(\n path: string,\n params?: Record<string, string | number | boolean>,\n ) => this.request<T>(path, params);\n return new ProjectResource(request, projectKey);\n }\n}\n\n/**\n * Appends query parameters to a URL string, skipping `undefined` values.\n * @internal\n */\nfunction buildUrl(base: string, params?: Record<string, string | number | boolean>): string {\n if (!params) return base;\n const entries = Object.entries(params).filter(([, v]) => v !== undefined);\n if (entries.length === 0) return base;\n const search = new URLSearchParams(entries.map(([k, v]) => [k, String(v)]));\n return `${base}?${search.toString()}`;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/security/Security.ts","../src/resources/PullRequestResource.ts","../src/resources/RepositoryResource.ts","../src/resources/ProjectResource.ts","../src/resources/UserResource.ts","../src/BitbucketClient.ts"],"sourcesContent":["export { BitbucketClient } from './BitbucketClient';\nexport type { BitbucketClientOptions } from './BitbucketClient';\nexport { Security } from './security/Security';\nexport { ProjectResource } from './resources/ProjectResource';\nexport { RepositoryResource } from './resources/RepositoryResource';\nexport { PullRequestResource } from './resources/PullRequestResource';\nexport { UserResource } from './resources/UserResource';\nexport type { BitbucketProject, ProjectsParams } from './domain/Project';\nexport type { BitbucketRepository, ReposParams } from './domain/Repository';\nexport type { BitbucketPullRequest, BitbucketParticipant, BitbucketRef, PullRequestsParams } from './domain/PullRequest';\nexport type { BitbucketPullRequestActivity, BitbucketPullRequestComment, BitbucketActivityUser, PullRequestActivityAction, ActivitiesParams } from './domain/PullRequestActivity';\nexport type { BitbucketPullRequestTask, PullRequestTaskState, PullRequestTaskPermittedOperations, PullRequestTaskAnchor, TasksParams } from './domain/PullRequestTask';\nexport type { BitbucketChange, BitbucketChangePath, ChangeType, ChangeNodeType, ChangesParams } from './domain/Change';\nexport type { BitbucketReport, BitbucketReportData, ReportResult, ReportDataType, ReportsParams } from './domain/Report';\nexport type { BitbucketBuildSummaries, BitbucketBuildCount } from './domain/BuildSummary';\nexport type { BitbucketIssue } from './domain/Issue';\nexport type { BitbucketUser, BitbucketUserPermission, UsersParams, ProjectUsersParams } from './domain/User';\nexport type { BitbucketCommit, BitbucketCommitAuthor, CommitsParams } from './domain/Commit';\nexport type { BitbucketBranch, BranchesParams } from './domain/Branch';\nexport type { BitbucketRepositorySize } from './domain/RepositorySize';\nexport type { BitbucketLastModifiedEntry, LastModifiedParams } from './domain/LastModified';\nexport type { RawFileParams } from './domain/RawFile';\nexport type { PaginationParams, PagedResponse } from './domain/Pagination';\n","/**\n * Encodes a string to Base64 in a way that works in both Node.js and browsers.\n * @internal\n */\nfunction toBase64(value: string): string {\n if (typeof btoa !== 'undefined') {\n return btoa(value);\n }\n return Buffer.from(value).toString('base64');\n}\n\n/**\n * Handles Basic Authentication for Bitbucket Data Center REST API requests.\n *\n * @example\n * ```typescript\n * const security = new Security(\n * 'https://bitbucket.example.com',\n * 'my-user',\n * 'my-token'\n * );\n *\n * const headers = security.getHeaders();\n * // { Authorization: 'Basic <base64>', 'Content-Type': 'application/json', Accept: 'application/json' }\n * ```\n */\nexport class Security {\n private readonly apiUrl: string;\n private readonly authorizationHeader: string;\n\n /**\n * Creates a new Security instance with Basic Authentication credentials.\n *\n * @param apiUrl - The base URL of the Bitbucket Data Center instance (e.g., `https://bitbucket.example.com`).\n * Must be a valid URL; throws if it cannot be parsed.\n * @param user - The username to authenticate with\n * @param token - The personal access token or password to authenticate with\n *\n * @throws {TypeError} If `apiUrl` is not a valid URL\n */\n constructor(apiUrl: string, user: string, token: string) {\n if (!URL.canParse(apiUrl)) {\n throw new TypeError(`Invalid apiUrl: \"${apiUrl}\" is not a valid URL`);\n }\n this.apiUrl = apiUrl.replace(/\\/$/, '');\n this.authorizationHeader = `Basic ${toBase64(`${user}:${token}`)}`;\n }\n\n /**\n * Returns the base URL of the Bitbucket Data Center instance, without a trailing slash.\n *\n * @returns The API base URL\n */\n getApiUrl(): string {\n return this.apiUrl;\n }\n\n /**\n * Returns the value of the `Authorization` header for Basic Authentication.\n *\n * @returns The Authorization header value in the format `Basic <base64-encoded-credentials>`\n */\n getAuthorizationHeader(): string {\n return this.authorizationHeader;\n }\n\n /**\n * Returns the full set of HTTP headers required for authenticated API requests.\n *\n * @returns An object containing `Authorization`, `Content-Type`, and `Accept` headers\n */\n getHeaders(): Record<string, string> {\n return {\n Authorization: this.authorizationHeader,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n };\n }\n}\n","import type { BitbucketPullRequest } from '../domain/PullRequest';\nimport type { BitbucketPullRequestActivity, ActivitiesParams } from '../domain/PullRequestActivity';\nimport type { BitbucketPullRequestTask, TasksParams } from '../domain/PullRequestTask';\nimport type { BitbucketCommit } from '../domain/Commit';\nimport type { BitbucketChange, ChangesParams } from '../domain/Change';\nimport type { BitbucketReport, ReportsParams } from '../domain/Report';\nimport type { BitbucketBuildSummaries } from '../domain/BuildSummary';\nimport type { BitbucketIssue } from '../domain/Issue';\nimport type { PagedResponse, PaginationParams } from '../domain/Pagination';\nimport type { RequestFn } from './ProjectResource';\n\n/**\n * Represents a Bitbucket pull request resource with chainable async methods.\n *\n * Implements `PromiseLike<BitbucketPullRequest>` so it can be awaited directly\n * to fetch the pull request info, while also exposing sub-resource methods.\n *\n * @example\n * ```typescript\n * // Await directly to get pull request info\n * const pr = await bbClient.project('PROJ').repo('my-repo').pullRequest(42);\n *\n * // Get activities\n * const activities = await bbClient.project('PROJ').repo('my-repo').pullRequest(42).activities();\n *\n * // Get tasks\n * const tasks = await bbClient.project('PROJ').repo('my-repo').pullRequest(42).tasks();\n *\n * // Get commits\n * const commits = await bbClient.project('PROJ').repo('my-repo').pullRequest(42).commits();\n *\n * // Get changes\n * const changes = await bbClient.project('PROJ').repo('my-repo').pullRequest(42).changes();\n *\n * // Get reports\n * const reports = await bbClient.project('PROJ').repo('my-repo').pullRequest(42).reports();\n *\n * // Get build summaries\n * const builds = await bbClient.project('PROJ').repo('my-repo').pullRequest(42).buildSummaries();\n *\n * // Get linked Jira issues\n * const issues = await bbClient.project('PROJ').repo('my-repo').pullRequest(42).issues();\n * ```\n */\nexport class PullRequestResource implements PromiseLike<BitbucketPullRequest> {\n private readonly basePath: string;\n\n /** @internal */\n constructor(\n private readonly request: RequestFn,\n projectKey: string,\n repoSlug: string,\n pullRequestId: number,\n ) {\n this.basePath = `/projects/${projectKey}/repos/${repoSlug}/pull-requests/${pullRequestId}`;\n }\n\n /**\n * Allows the resource to be awaited directly, resolving with the pull request info.\n * Delegates to {@link PullRequestResource.get}.\n */\n then<TResult1 = BitbucketPullRequest, TResult2 = never>(\n onfulfilled?: ((value: BitbucketPullRequest) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): PromiseLike<TResult1 | TResult2> {\n return this.get().then(onfulfilled, onrejected);\n }\n\n /**\n * Fetches the pull request details.\n *\n * `GET /rest/api/latest/projects/{key}/repos/{slug}/pull-requests/{id}`\n *\n * @returns The pull request object\n */\n async get(): Promise<BitbucketPullRequest> {\n return this.request<BitbucketPullRequest>(this.basePath);\n }\n\n /**\n * Fetches the activity feed for this pull request.\n *\n * Activities include comments, approvals, reviews, rescopes, merges, and declines.\n *\n * `GET /rest/api/latest/projects/{key}/repos/{slug}/pull-requests/{id}/activities`\n *\n * @param params - Optional filters: `limit`, `start`, `fromId`, `fromType`\n * @returns An array of pull request activities, ordered from most recent to oldest\n */\n async activities(params?: ActivitiesParams): Promise<BitbucketPullRequestActivity[]> {\n const data = await this.request<PagedResponse<BitbucketPullRequestActivity>>(\n `${this.basePath}/activities`,\n params as Record<string, string | number | boolean>,\n );\n return data.values;\n }\n\n /**\n * Fetches the tasks (review to-do items) for this pull request.\n *\n * Tasks are created by reviewers on specific comments and can be `OPEN` or `RESOLVED`.\n *\n * `GET /rest/api/latest/projects/{key}/repos/{slug}/pull-requests/{id}/tasks`\n *\n * @param params - Optional filters: `limit`, `start`\n * @returns An array of pull request tasks\n */\n async tasks(params?: TasksParams): Promise<BitbucketPullRequestTask[]> {\n const data = await this.request<PagedResponse<BitbucketPullRequestTask>>(\n `${this.basePath}/tasks`,\n params as Record<string, string | number | boolean>,\n );\n return data.values;\n }\n\n /**\n * Fetches the commits included in this pull request.\n *\n * `GET /rest/api/latest/projects/{key}/repos/{slug}/pull-requests/{id}/commits`\n *\n * @param params - Optional pagination: `limit`, `start`\n * @returns An array of commits\n */\n async commits(params?: PaginationParams): Promise<BitbucketCommit[]> {\n const data = await this.request<PagedResponse<BitbucketCommit>>(\n `${this.basePath}/commits`,\n params as Record<string, string | number | boolean>,\n );\n return data.values;\n }\n\n /**\n * Fetches the file changes included in this pull request.\n *\n * `GET /rest/api/latest/projects/{key}/repos/{slug}/pull-requests/{id}/changes`\n *\n * @param params - Optional filters: `limit`, `start`, `withComments`\n * @returns An array of file changes\n */\n async changes(params?: ChangesParams): Promise<BitbucketChange[]> {\n const data = await this.request<PagedResponse<BitbucketChange>>(\n `${this.basePath}/changes`,\n params as Record<string, string | number | boolean>,\n );\n return data.values;\n }\n\n /**\n * Fetches the Code Insights reports for this pull request.\n *\n * `GET /rest/api/latest/projects/{key}/repos/{slug}/pull-requests/{id}/reports`\n *\n * @param params - Optional pagination: `limit`, `start`\n * @returns An array of Code Insights reports\n */\n async reports(params?: ReportsParams): Promise<BitbucketReport[]> {\n const data = await this.request<PagedResponse<BitbucketReport>>(\n `${this.basePath}/reports`,\n params as Record<string, string | number | boolean>,\n );\n return data.values;\n }\n\n /**\n * Fetches the aggregated build summaries for this pull request.\n *\n * Returns a map of commit hash → build counts per state\n * (`successful`, `failed`, `inProgress`, `cancelled`, `unknown`).\n *\n * `GET /rest/api/latest/projects/{key}/repos/{slug}/pull-requests/{id}/build-summaries`\n *\n * @returns A record keyed by commit SHA with aggregated build counts\n */\n async buildSummaries(): Promise<BitbucketBuildSummaries> {\n return this.request<BitbucketBuildSummaries>(`${this.basePath}/build-summaries`);\n }\n\n /**\n * Fetches the Jira issues linked to this pull request.\n *\n * `GET /rest/api/latest/projects/{key}/repos/{slug}/pull-requests/{id}/issues`\n *\n * @returns An array of linked Jira issues\n */\n async issues(): Promise<BitbucketIssue[]> {\n return this.request<BitbucketIssue[]>(`${this.basePath}/issues`);\n }\n}\n","import type { BitbucketRepository } from '../domain/Repository';\nimport type { BitbucketPullRequest, PullRequestsParams } from '../domain/PullRequest';\nimport type { BitbucketCommit, CommitsParams } from '../domain/Commit';\nimport type { BitbucketBranch, BranchesParams } from '../domain/Branch';\nimport type { BitbucketRepositorySize } from '../domain/RepositorySize';\nimport type { BitbucketLastModifiedEntry, LastModifiedParams } from '../domain/LastModified';\nimport type { RawFileParams } from '../domain/RawFile';\nimport type { PagedResponse } from '../domain/Pagination';\nimport type { RequestFn, RequestTextFn } from './ProjectResource';\nimport { PullRequestResource } from './PullRequestResource';\n\n/**\n * Represents a Bitbucket repository resource with chainable async methods.\n *\n * Implements `PromiseLike<BitbucketRepository>` so it can be awaited directly\n * to fetch repository info, while also exposing sub-resource methods.\n *\n * @example\n * ```typescript\n * // Await directly to get repository info\n * const repo = await bbClient.project('PROJ').repo('my-repo');\n *\n * // Get pull requests\n * const prs = await bbClient.project('PROJ').repo('my-repo').pullRequests({ state: 'OPEN' });\n *\n * // Navigate into a specific pull request\n * const activities = await bbClient.project('PROJ').repo('my-repo').pullRequest(42).activities();\n *\n * // Get commits\n * const commits = await bbClient.project('PROJ').repo('my-repo').commits({ limit: 10 });\n * ```\n */\nexport class RepositoryResource implements PromiseLike<BitbucketRepository> {\n private readonly basePath: string;\n\n /** @internal */\n constructor(\n private readonly request: RequestFn,\n private readonly requestText: RequestTextFn,\n private readonly projectKey: string,\n private readonly repoSlug: string,\n ) {\n this.basePath = `/projects/${projectKey}/repos/${repoSlug}`;\n }\n\n /**\n * Allows the resource to be awaited directly, resolving with the repository info.\n * Delegates to {@link RepositoryResource.get}.\n */\n then<TResult1 = BitbucketRepository, TResult2 = never>(\n onfulfilled?: ((value: BitbucketRepository) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): PromiseLike<TResult1 | TResult2> {\n return this.get().then(onfulfilled, onrejected);\n }\n\n /**\n * Fetches the repository details.\n *\n * `GET /rest/api/latest/projects/{key}/repos/{slug}`\n *\n * @returns The repository object\n */\n async get(): Promise<BitbucketRepository> {\n return this.request<BitbucketRepository>(this.basePath);\n }\n\n /**\n * Fetches pull requests for this repository.\n *\n * `GET /rest/api/latest/projects/{key}/repos/{slug}/pull-requests`\n *\n * @param params - Optional filters: `limit`, `start`, `state`, `direction`, `at`, `order`\n * @returns An array of pull requests\n */\n async pullRequests(params?: PullRequestsParams): Promise<BitbucketPullRequest[]> {\n const data = await this.request<PagedResponse<BitbucketPullRequest>>(\n `${this.basePath}/pull-requests`,\n params as Record<string, string | number | boolean>,\n );\n return data.values;\n }\n\n /**\n * Fetches commits for this repository.\n *\n * `GET /rest/api/latest/projects/{key}/repos/{slug}/commits`\n *\n * @param params - Optional filters: `limit`, `start`, `until`, `since`, `path`, `merges`, `followRenames`, `ignoreMissing`\n * @returns An array of commits\n */\n async commits(params?: CommitsParams): Promise<BitbucketCommit[]> {\n const data = await this.request<PagedResponse<BitbucketCommit>>(\n `${this.basePath}/commits`,\n params as Record<string, string | number | boolean>,\n );\n return data.values;\n }\n\n /**\n * Fetches the files last modified in this repository along with the commit that last touched each.\n *\n * `GET /rest/api/latest/projects/{key}/repos/{slug}/last-modified`\n *\n * @param params - Optional filters: `limit`, `start`, `at`\n * @returns An array of last-modified entries\n */\n async lastModified(params?: LastModifiedParams): Promise<BitbucketLastModifiedEntry[]> {\n const data = await this.request<PagedResponse<BitbucketLastModifiedEntry>>(\n `${this.basePath}/last-modified`,\n params as Record<string, string | number | boolean>,\n );\n return data.values;\n }\n\n /**\n * Fetches the size of this repository.\n *\n * `GET /rest/api/latest/projects/{key}/repos/{slug}/sizes`\n *\n * @returns The repository size object\n */\n async size(): Promise<BitbucketRepositorySize> {\n return this.request<BitbucketRepositorySize>(`${this.basePath}/sizes`);\n }\n\n /**\n * Fetches branches for this repository.\n *\n * `GET /rest/api/latest/projects/{key}/repos/{slug}/branches`\n *\n * @param params - Optional filters: `limit`, `start`, `filterText`, `orderBy`, `details`, `base`, `boostMatches`\n * @returns An array of branches\n */\n async branches(params?: BranchesParams): Promise<BitbucketBranch[]> {\n const data = await this.request<PagedResponse<BitbucketBranch>>(\n `${this.basePath}/branches`,\n params as Record<string, string | number | boolean>,\n );\n return data.values;\n }\n\n /**\n * Returns a {@link PullRequestResource} for a given pull request ID, providing\n * access to pull request data and sub-resources (activities, etc.).\n *\n * The returned resource can be awaited directly to fetch pull request info,\n * or chained to access nested resources.\n *\n * @param pullRequestId - The numeric pull request ID\n * @returns A chainable pull request resource\n *\n * @example\n * ```typescript\n * const pr = await bbClient.project('PROJ').repo('my-repo').pullRequest(42);\n * const activities = await bbClient.project('PROJ').repo('my-repo').pullRequest(42).activities();\n * ```\n */\n /**\n * Fetches the raw content of a file in this repository.\n *\n * `GET /rest/api/latest/projects/{key}/repos/{slug}/raw/{path}`\n *\n * @param filePath - Path to the file (e.g., `'src/index.ts'`)\n * @param params - Optional: `at` (branch, tag, or commit SHA)\n * @returns The raw file content as a string\n */\n async raw(filePath: string, params?: RawFileParams): Promise<string> {\n return this.requestText(\n `${this.basePath}/raw/${filePath}`,\n params as Record<string, string | number | boolean>,\n );\n }\n\n pullRequest(pullRequestId: number): PullRequestResource {\n return new PullRequestResource(this.request, this.projectKey, this.repoSlug, pullRequestId);\n }\n}\n","import type { BitbucketProject } from '../domain/Project';\nimport type { BitbucketRepository, ReposParams } from '../domain/Repository';\nimport type { BitbucketUserPermission, ProjectUsersParams } from '../domain/User';\nimport type { PagedResponse } from '../domain/Pagination';\nimport { RepositoryResource } from './RepositoryResource';\n\n/** @internal */\nexport type RequestFn = <T>(\n path: string,\n params?: Record<string, string | number | boolean>,\n) => Promise<T>;\n\n/** @internal */\nexport type RequestTextFn = (\n path: string,\n params?: Record<string, string | number | boolean>,\n) => Promise<string>;\n\n/**\n * Represents a Bitbucket project resource with chainable async methods.\n *\n * Implements `PromiseLike<BitbucketProject>` so it can be awaited directly\n * to fetch the project info, while also exposing sub-resource methods.\n *\n * @example\n * ```typescript\n * // Await directly to get project info\n * const project = await bbClient.project('PROJ');\n *\n * // Get repositories with filters\n * const repos = await bbClient.project('PROJ').repos({ limit: 50, name: 'api' });\n *\n * // Navigate into a specific repository\n * const prs = await bbClient.project('PROJ').repo('my-repo').pullRequests();\n *\n * // Get users with access to the project\n * const users = await bbClient.project('PROJ').users({ permission: 'PROJECT_WRITE' });\n * ```\n */\nexport class ProjectResource implements PromiseLike<BitbucketProject> {\n /** @internal */\n constructor(\n private readonly request: RequestFn,\n private readonly requestText: RequestTextFn,\n private readonly key: string,\n ) {}\n\n /**\n * Allows the resource to be awaited directly, resolving with the project info.\n * Delegates to {@link ProjectResource.get}.\n */\n then<TResult1 = BitbucketProject, TResult2 = never>(\n onfulfilled?: ((value: BitbucketProject) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): PromiseLike<TResult1 | TResult2> {\n return this.get().then(onfulfilled, onrejected);\n }\n\n /**\n * Fetches the project details.\n *\n * `GET /rest/api/latest/projects/{key}`\n *\n * @returns The project object\n */\n async get(): Promise<BitbucketProject> {\n return this.request<BitbucketProject>(`/projects/${this.key}`);\n }\n\n /**\n * Fetches repositories belonging to this project.\n *\n * `GET /rest/api/latest/projects/{key}/repos`\n *\n * @param params - Optional filters: `limit`, `start`, `slug`, `name`, `permission`\n * @returns An array of repositories\n */\n async repos(params?: ReposParams): Promise<BitbucketRepository[]> {\n const data = await this.request<PagedResponse<BitbucketRepository>>(\n `/projects/${this.key}/repos`,\n params as Record<string, string | number | boolean>,\n );\n return data.values;\n }\n\n /**\n * Returns a {@link RepositoryResource} for a given repository slug, providing\n * access to repository-level data and sub-resources (pull requests, commits, etc.).\n *\n * The returned resource can be awaited directly to fetch repository info,\n * or chained to access nested resources.\n *\n * @param repoSlug - The repository slug (e.g., `'my-repo'`)\n * @returns A chainable repository resource\n *\n * @example\n * ```typescript\n * const repo = await bbClient.project('PROJ').repo('my-repo');\n * const prs = await bbClient.project('PROJ').repo('my-repo').pullRequests({ state: 'OPEN' });\n * const commits = await bbClient.project('PROJ').repo('my-repo').commits({ limit: 10 });\n * ```\n */\n repo(repoSlug: string): RepositoryResource {\n return new RepositoryResource(this.request, this.requestText, this.key, repoSlug);\n }\n\n /**\n * Fetches users with explicit permissions on this project.\n *\n * `GET /rest/api/latest/projects/{key}/permissions/users`\n *\n * @param params - Optional filters: `limit`, `start`, `filter`, `permission`\n * @returns An array of user–permission pairs\n */\n async users(params?: ProjectUsersParams): Promise<BitbucketUserPermission[]> {\n const data = await this.request<PagedResponse<BitbucketUserPermission>>(\n `/projects/${this.key}/permissions/users`,\n params as Record<string, string | number | boolean>,\n );\n return data.values;\n }\n}\n","import type { BitbucketUser } from '../domain/User';\nimport type { RequestFn } from './ProjectResource';\n\n/**\n * Represents a Bitbucket user resource.\n *\n * Implements `PromiseLike<BitbucketUser>` so it can be awaited directly\n * to fetch user info.\n *\n * @example\n * ```typescript\n * // Await directly to get user info\n * const user = await bbClient.user('pilmee');\n * ```\n */\nexport class UserResource implements PromiseLike<BitbucketUser> {\n private readonly basePath: string;\n\n /** @internal */\n constructor(\n private readonly request: RequestFn,\n slug: string,\n ) {\n this.basePath = `/users/${slug}`;\n }\n\n /**\n * Allows the resource to be awaited directly, resolving with the user info.\n * Delegates to {@link UserResource.get}.\n */\n then<TResult1 = BitbucketUser, TResult2 = never>(\n onfulfilled?: ((value: BitbucketUser) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): PromiseLike<TResult1 | TResult2> {\n return this.get().then(onfulfilled, onrejected);\n }\n\n /**\n * Fetches the user details.\n *\n * `GET /rest/api/latest/users/{slug}`\n *\n * @returns The user object\n */\n async get(): Promise<BitbucketUser> {\n return this.request<BitbucketUser>(this.basePath);\n }\n}\n","import { Security } from './security/Security';\nimport { ProjectResource, type RequestFn, type RequestTextFn } from './resources/ProjectResource';\nimport { UserResource } from './resources/UserResource';\nimport type { BitbucketProject, ProjectsParams } from './domain/Project';\nimport type { BitbucketUser, UsersParams } from './domain/User';\nimport type { PagedResponse } from './domain/Pagination';\n\n/**\n * Constructor options for {@link BitbucketClient}.\n */\nexport interface BitbucketClientOptions {\n /** The host URL of the Bitbucket Data Center instance (e.g., `https://bitbucket.example.com`) */\n apiUrl: string;\n /** The API path to prepend to every request (e.g., `'rest/api/latest'`) */\n apiPath: string;\n /** The username to authenticate with */\n user: string;\n /** The personal access token or password to authenticate with */\n token: string;\n}\n\n/**\n * Main entry point for the Bitbucket Data Center REST API client.\n *\n * @example\n * ```typescript\n * const bbClient = new BitbucketClient({\n * apiUrl: 'https://bitbucket.example.com',\n * apiPath: 'rest/api/latest',\n * user: 'pilmee',\n * token: 'my-token',\n * });\n *\n * const projects = await bbClient.projects({ limit: 50 });\n * const project = await bbClient.project('PROJ');\n * const repos = await bbClient.project('PROJ').repos({ name: 'api' });\n * const repo = await bbClient.project('PROJ').repo('my-repo');\n * const prs = await bbClient.project('PROJ').repo('my-repo').pullRequests({ state: 'OPEN' });\n * const commits = await bbClient.project('PROJ').repo('my-repo').commits({ limit: 10 });\n * const users = await bbClient.users({ filter: 'john' });\n * const user = await bbClient.user('pilmee');\n * ```\n */\nexport class BitbucketClient {\n private readonly security: Security;\n private readonly apiPath: string;\n\n /**\n * @param options - Connection and authentication options\n * @throws {TypeError} If `apiUrl` is not a valid URL\n */\n constructor({ apiUrl, apiPath, user, token }: BitbucketClientOptions) {\n this.security = new Security(apiUrl, user, token);\n this.apiPath = apiPath.replace(/^\\/|\\/$/g, '');\n }\n\n /**\n * Performs an authenticated GET request to the Bitbucket REST API.\n *\n * @param path - API path appended directly to `apiUrl` (e.g., `'/projects'`)\n * @param params - Optional query parameters to append to the URL\n * @throws {Error} If the HTTP response is not OK\n * @internal\n */\n private async request<T>(\n path: string,\n params?: Record<string, string | number | boolean>,\n ): Promise<T> {\n const base = `${this.security.getApiUrl()}/${this.apiPath}${path}`;\n const url = buildUrl(base, params);\n const response = await fetch(url, { headers: this.security.getHeaders() });\n if (!response.ok) {\n throw new Error(`Bitbucket API error: ${response.status} ${response.statusText}`);\n }\n return response.json() as Promise<T>;\n }\n\n private async requestText(\n path: string,\n params?: Record<string, string | number | boolean>,\n ): Promise<string> {\n const base = `${this.security.getApiUrl()}/${this.apiPath}${path}`;\n const url = buildUrl(base, params);\n const response = await fetch(url, { headers: this.security.getHeaders() });\n if (!response.ok) {\n throw new Error(`Bitbucket API error: ${response.status} ${response.statusText}`);\n }\n return response.text();\n }\n\n /**\n * Fetches all projects accessible to the authenticated user.\n *\n * `GET /rest/api/latest/projects`\n *\n * @param params - Optional filters: `limit`, `start`, `name`, `permission`\n * @returns An array of projects\n */\n async projects(params?: ProjectsParams): Promise<BitbucketProject[]> {\n const data = await this.request<PagedResponse<BitbucketProject>>(\n '/projects',\n params as Record<string, string | number | boolean>,\n );\n return data.values;\n }\n\n /**\n * Returns a {@link ProjectResource} for a given project key, providing access\n * to project-level data and sub-resources.\n *\n * The returned resource can be awaited directly to fetch project info,\n * or chained to access nested resources.\n *\n * @param projectKey - The project key (e.g., `'PROJ'`)\n * @returns A chainable project resource\n *\n * @example\n * ```typescript\n * const project = await bbClient.project('PROJ');\n * const repos = await bbClient.project('PROJ').repos({ limit: 10 });\n * const prs = await bbClient.project('PROJ').repo('my-repo').pullRequests();\n * ```\n */\n project(projectKey: string): ProjectResource {\n const request: RequestFn = <T>(\n path: string,\n params?: Record<string, string | number | boolean>,\n ) => this.request<T>(path, params);\n const requestText: RequestTextFn = (path, params) => this.requestText(path, params);\n return new ProjectResource(request, requestText, projectKey);\n }\n\n /**\n * Fetches all users accessible to the authenticated user.\n *\n * `GET /rest/api/latest/users`\n *\n * @param params - Optional filters: `limit`, `start`, `filter`\n * @returns An array of users\n */\n async users(params?: UsersParams): Promise<BitbucketUser[]> {\n const data = await this.request<PagedResponse<BitbucketUser>>(\n '/users',\n params as Record<string, string | number | boolean>,\n );\n return data.values;\n }\n\n /**\n * Returns a {@link UserResource} for a given user slug, providing access\n * to user data.\n *\n * The returned resource can be awaited directly to fetch user info.\n *\n * @param slug - The user slug (e.g., `'pilmee'`)\n * @returns A chainable user resource\n *\n * @example\n * ```typescript\n * const user = await bbClient.user('pilmee');\n * ```\n */\n user(slug: string): UserResource {\n const request: RequestFn = <T>(\n path: string,\n params?: Record<string, string | number | boolean>,\n ) => this.request<T>(path, params);\n return new UserResource(request, slug);\n }\n}\n\n/**\n * Appends query parameters to a URL string, skipping `undefined` values.\n * @internal\n */\nfunction buildUrl(base: string, params?: Record<string, string | number | boolean>): string {\n if (!params) return base;\n const entries = Object.entries(params).filter(([, v]) => v !== undefined);\n if (entries.length === 0) return base;\n const search = new URLSearchParams(entries.map(([k, v]) => [k, String(v)]));\n return `${base}?${search.toString()}`;\n}\n"],"mappings":"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","names":[]}
|