@knpkv/jira-api-client 2.0.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/JiraApiClient.js +1 -1
- package/dist/JiraApiClient.js.map +1 -1
- package/dist/JiraApiConfig.d.ts +6 -1
- package/dist/JiraApiConfig.d.ts.map +1 -1
- package/dist/JiraApiConfig.js +1 -1
- package/dist/JiraApiConfig.js.map +1 -1
- package/package.json +2 -2
- package/scripts/regenerate.ts +1 -0
- package/src/JiraApiClient.ts +1 -1
- package/src/JiraApiConfig.ts +11 -2
- package/test/JiraApiCredential.test.ts +22 -0
- package/test/RecursiveSchemas.test.ts +2 -2
- package/test/tsconfig.json +6 -0
- package/vitest.config.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @knpkv/jira-api-client
|
|
2
2
|
|
|
3
|
+
## 2.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#581](https://github.com/knpkv/npm/pull/581) [`c22e8ae`](https://github.com/knpkv/npm/commit/c22e8ae0c55a50e9c1edbd46a1cd18108f62e4fa) Thanks [@konopkov](https://github.com/konopkov)! - Mark existing silent fallbacks (failures turned into success without a log) with a follow-up lint suppression. No behaviour change.
|
|
8
|
+
|
|
9
|
+
## 2.1.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#540](https://github.com/knpkv/npm/pull/540) [`0573403`](https://github.com/knpkv/npm/commit/057340343fcc727fd0c56329d840a668170376ad) Thanks [@konopkov](https://github.com/konopkov)! - Connect Jira with an API token, and set up each system on its own:
|
|
14
|
+
|
|
15
|
+
- `jcf auth jira token` asks for your Jira address, email and an API token, checks them with Jira, and saves them to `~/.jcf/jira.json` (owner-only). The token is never printed. Classic and scoped tokens both work; a scoped token is used through Atlassian's gateway for the site. A failed check says whether the site, the token or the network was wrong. The OAuth app (`create`, `configure`, `login`) stays as the advanced option; when both exist the token is used.
|
|
16
|
+
- `jcf` with nothing connected asks about Jira and Clockify in turn, and either can be skipped. With one connected it opens straight away. Without a terminal it prints both commands and exits 1.
|
|
17
|
+
- Commands that need Jira (`issue list`, `timer start`, `sync reconcile`) fail with "Jira is not connected. Run jcf auth jira token to connect it." and exit 1, instead of reporting no issues. `auth clockify setup` takes `--api-key` and fails without a terminal. Failed `timer` and `config set project` steps and a failed reconcile exit non-zero.
|
|
18
|
+
- `jcf auth status` names the Clockify workspace and the next command for anything not connected. Every command has a help description, and `--version` reports the package version.
|
|
19
|
+
- `@knpkv/jira-api-client`: a basic-auth credential may carry its `siteUrl`, used as the request host, so a credential re-read per request keeps its site.
|
|
20
|
+
- `@knpkv/agent-skills`: the jcf skill names `jcf auth jira token` as the way to connect Jira.
|
|
21
|
+
|
|
3
22
|
## 2.0.0
|
|
4
23
|
|
|
5
24
|
### Major Changes
|
package/dist/JiraApiClient.js
CHANGED
|
@@ -21,7 +21,7 @@ import { JiraApiConfig } from "./JiraApiConfig.js";
|
|
|
21
21
|
const authorizationHeader = (auth) => auth.type === "basic"
|
|
22
22
|
? `Basic ${Base64.encode(`${auth.email}:${Redacted.value(auth.apiToken)}`)}`
|
|
23
23
|
: `Bearer ${Redacted.value(auth.accessToken)}`;
|
|
24
|
-
const apiBaseUrl = (baseUrl, auth) => auth.type === "oauth2" ? `https://api.atlassian.com/ex/jira/${auth.cloudId}` : baseUrl;
|
|
24
|
+
const apiBaseUrl = (baseUrl, auth) => auth.type === "oauth2" ? `https://api.atlassian.com/ex/jira/${auth.cloudId}` : auth.siteUrl ?? baseUrl;
|
|
25
25
|
/**
|
|
26
26
|
* Where the credential is turned into a header.
|
|
27
27
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JiraApiClient.js","sourceRoot":"","sources":["../src/JiraApiClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AACzC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AACtC,OAAO,KAAK,UAAU,MAAM,wBAAwB,CAAA;AAEpD,OAAO,KAAK,iBAAiB,MAAM,+BAA+B,CAAA;AAClE,OAAO,KAAK,kBAAkB,MAAM,gCAAgC,CAAA;AACpE,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAE3C,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAA;AACnD,OAAO,EAAE,aAAa,EAAsD,MAAM,oBAAoB,CAAA;AAetG,MAAM,mBAAmB,GAAG,CAAC,IAAuB,EAAU,EAAE,CAC9D,IAAI,CAAC,IAAI,KAAK,OAAO;IACnB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE;IAC5E,CAAC,CAAC,UAAU,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAA;AAElD,MAAM,UAAU,GAAG,CAAC,OAAe,EAAE,IAAuB,EAAU,EAAE,CACtE,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,qCAAqC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"JiraApiClient.js","sourceRoot":"","sources":["../src/JiraApiClient.ts"],"names":[],"mappings":"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"}
|
package/dist/JiraApiConfig.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* - **Discriminated auth union**: The `auth` field is `{ type: "basic", ... } | { type: "oauth2", ... }`.
|
|
7
7
|
* Basic auth uses email + Redacted API token; OAuth2 uses Redacted access token + cloud ID.
|
|
8
8
|
* - **Base URL routing**: For OAuth2, the base URL is derived from cloud ID (`api.atlassian.com/ex/jira/{cloudId}`);
|
|
9
|
-
* for basic auth, `
|
|
9
|
+
* for basic auth, the credential's `siteUrl` when set, otherwise `baseUrl`.
|
|
10
10
|
* - **`auth` is a snapshot; `resolveAuth` is a subscription.** A credential that can expire needs the
|
|
11
11
|
* second one — see its own note.
|
|
12
12
|
*
|
|
@@ -20,6 +20,11 @@ export type JiraApiCredential = {
|
|
|
20
20
|
readonly type: "basic";
|
|
21
21
|
readonly email: string;
|
|
22
22
|
readonly apiToken: Redacted.Redacted<string>;
|
|
23
|
+
/**
|
|
24
|
+
* The site this token belongs to, such as `https://your-team.atlassian.net`. When set it is the
|
|
25
|
+
* request host instead of `baseUrl`, so a credential re-read through `resolveAuth` keeps its site.
|
|
26
|
+
*/
|
|
27
|
+
readonly siteUrl?: string | undefined;
|
|
23
28
|
} | {
|
|
24
29
|
readonly type: "oauth2";
|
|
25
30
|
readonly accessToken: Redacted.Redacted<string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JiraApiConfig.d.ts","sourceRoot":"","sources":["../src/JiraApiConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AACzC,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAA;AAC5C,OAAO,KAAK,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAEhD,0CAA0C;AAC1C,MAAM,MAAM,iBAAiB,GACzB;
|
|
1
|
+
{"version":3,"file":"JiraApiConfig.d.ts","sourceRoot":"","sources":["../src/JiraApiConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AACzC,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAA;AAC5C,OAAO,KAAK,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAEhD,0CAA0C;AAC1C,MAAM,MAAM,iBAAiB,GACzB;IACA,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;IAC5C;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACtC,GACC;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAE1G;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAA;IAChC;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,GAAG,SAAS,CAAA;CACpE;;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,aAAc,SAAQ,kBAElC;CAAG"}
|
package/dist/JiraApiConfig.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* - **Discriminated auth union**: The `auth` field is `{ type: "basic", ... } | { type: "oauth2", ... }`.
|
|
7
7
|
* Basic auth uses email + Redacted API token; OAuth2 uses Redacted access token + cloud ID.
|
|
8
8
|
* - **Base URL routing**: For OAuth2, the base URL is derived from cloud ID (`api.atlassian.com/ex/jira/{cloudId}`);
|
|
9
|
-
* for basic auth, `
|
|
9
|
+
* for basic auth, the credential's `siteUrl` when set, otherwise `baseUrl`.
|
|
10
10
|
* - **`auth` is a snapshot; `resolveAuth` is a subscription.** A credential that can expire needs the
|
|
11
11
|
* second one — see its own note.
|
|
12
12
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JiraApiConfig.js","sourceRoot":"","sources":["../src/JiraApiConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"JiraApiConfig.js","sourceRoot":"","sources":["../src/JiraApiConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AA0CzC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,OAAO,aAAc,SAAQ,OAAO,CAAC,OAAO,EAAwC,CACxF,sCAAsC,CACvC;CAAG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knpkv/jira-api-client",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Effect-based Jira Cloud REST API v3 client",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "knpkv",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"test:watch": "vitest",
|
|
68
68
|
"lint": "eslint src",
|
|
69
69
|
"lint:fix": "eslint src --fix",
|
|
70
|
-
"check": "tsc --noEmit && tsc -p scripts/tsconfig.json",
|
|
70
|
+
"check": "tsc --noEmit && tsc -p scripts/tsconfig.json && tsc -p test/tsconfig.json --noEmit",
|
|
71
71
|
"regenerate": "tsx scripts/regenerate.ts",
|
|
72
72
|
"regenerate:check": "tsx scripts/regenerate.ts --check"
|
|
73
73
|
}
|
package/scripts/regenerate.ts
CHANGED
|
@@ -236,6 +236,7 @@ const root = Command.make("jira-api-regenerate", { check, local }).pipe(
|
|
|
236
236
|
const current = yield* fs.readFileString(scriptPaths.specFile).pipe(
|
|
237
237
|
Effect.flatMap(Schema.decodeUnknownEffect(JsonString)),
|
|
238
238
|
Effect.flatMap(canonicalJson),
|
|
239
|
+
// ast-grep-ignore: no-silent-catch-all -- follow-up: silent fallback; fail with a typed error, log it, or mark it best-effort
|
|
239
240
|
Effect.orElseSucceed(() => "")
|
|
240
241
|
)
|
|
241
242
|
|
package/src/JiraApiClient.ts
CHANGED
|
@@ -40,7 +40,7 @@ const authorizationHeader = (auth: JiraApiCredential): string =>
|
|
|
40
40
|
: `Bearer ${Redacted.value(auth.accessToken)}`
|
|
41
41
|
|
|
42
42
|
const apiBaseUrl = (baseUrl: string, auth: JiraApiCredential): string =>
|
|
43
|
-
auth.type === "oauth2" ? `https://api.atlassian.com/ex/jira/${auth.cloudId}` : baseUrl
|
|
43
|
+
auth.type === "oauth2" ? `https://api.atlassian.com/ex/jira/${auth.cloudId}` : auth.siteUrl ?? baseUrl
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
46
|
* Where the credential is turned into a header.
|
package/src/JiraApiConfig.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* - **Discriminated auth union**: The `auth` field is `{ type: "basic", ... } | { type: "oauth2", ... }`.
|
|
7
7
|
* Basic auth uses email + Redacted API token; OAuth2 uses Redacted access token + cloud ID.
|
|
8
8
|
* - **Base URL routing**: For OAuth2, the base URL is derived from cloud ID (`api.atlassian.com/ex/jira/{cloudId}`);
|
|
9
|
-
* for basic auth, `
|
|
9
|
+
* for basic auth, the credential's `siteUrl` when set, otherwise `baseUrl`.
|
|
10
10
|
* - **`auth` is a snapshot; `resolveAuth` is a subscription.** A credential that can expire needs the
|
|
11
11
|
* second one — see its own note.
|
|
12
12
|
*
|
|
@@ -18,7 +18,16 @@ import type * as Redacted from "effect/Redacted"
|
|
|
18
18
|
|
|
19
19
|
/** How a request proves who is asking. */
|
|
20
20
|
export type JiraApiCredential =
|
|
21
|
-
| {
|
|
21
|
+
| {
|
|
22
|
+
readonly type: "basic"
|
|
23
|
+
readonly email: string
|
|
24
|
+
readonly apiToken: Redacted.Redacted<string>
|
|
25
|
+
/**
|
|
26
|
+
* The site this token belongs to, such as `https://your-team.atlassian.net`. When set it is the
|
|
27
|
+
* request host instead of `baseUrl`, so a credential re-read through `resolveAuth` keeps its site.
|
|
28
|
+
*/
|
|
29
|
+
readonly siteUrl?: string | undefined
|
|
30
|
+
}
|
|
22
31
|
| { readonly type: "oauth2"; readonly accessToken: Redacted.Redacted<string>; readonly cloudId: string }
|
|
23
32
|
|
|
24
33
|
/**
|
|
@@ -100,4 +100,26 @@ describe("JiraApiClient credentials", () => {
|
|
|
100
100
|
expect(requests[0]?.url).toBe("https://jira.test/rest/api/3/issue/PROJ-1")
|
|
101
101
|
expect(requests.map((request) => request.headers.authorization)).toEqual([expected, expected])
|
|
102
102
|
}))
|
|
103
|
+
|
|
104
|
+
// A resolver can hand back an API token for whichever site was connected since the client was
|
|
105
|
+
// built (jcf-web runs while `jcf auth jira token` changes the site), so the host travels with it.
|
|
106
|
+
it.effect("routes a resolved API token at its own site", () =>
|
|
107
|
+
Effect.gen(function*() {
|
|
108
|
+
const requests: Array<HttpClientRequest.HttpClientRequest> = []
|
|
109
|
+
const client = make(recording(requests), {
|
|
110
|
+
baseUrl: "",
|
|
111
|
+
auth: staleCredential,
|
|
112
|
+
resolveAuth: Effect.succeed({
|
|
113
|
+
type: "basic",
|
|
114
|
+
email: "user@example.com",
|
|
115
|
+
apiToken: Redacted.make("test-token"),
|
|
116
|
+
siteUrl: "https://team.atlassian.net"
|
|
117
|
+
})
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
yield* client.getIssue("PROJ-1", undefined)
|
|
121
|
+
|
|
122
|
+
expect(requests[0]?.url).toBe("https://team.atlassian.net/rest/api/3/issue/PROJ-1")
|
|
123
|
+
expect(requests[0]?.headers.authorization).toBe(`Basic ${Base64.encode("user@example.com:test-token")}`)
|
|
124
|
+
}))
|
|
103
125
|
})
|
|
@@ -5,7 +5,7 @@ import { JiraApi } from "../src/index.js"
|
|
|
5
5
|
// @effect/openapi-generator 4.0.0 emits Schema.Never for these recursive unions; the committed client keeps them usable.
|
|
6
6
|
describe("recursive generated schemas", () => {
|
|
7
7
|
it("decodes a nested JQL query clause", () => {
|
|
8
|
-
const clause = {
|
|
8
|
+
const clause: typeof JiraApi.JqlQueryClause.Encoded = {
|
|
9
9
|
clauses: [
|
|
10
10
|
{ field: { name: "project" }, operator: "=", operand: { value: "KNP" } },
|
|
11
11
|
{ clauses: [{ field: { name: "status" }, operator: "!=", operand: { value: "Done" } }], operator: "not" }
|
|
@@ -16,7 +16,7 @@ describe("recursive generated schemas", () => {
|
|
|
16
16
|
})
|
|
17
17
|
|
|
18
18
|
it("decodes a nested workflow condition tree", () => {
|
|
19
|
-
const condition = {
|
|
19
|
+
const condition: typeof JiraApi.WorkflowCondition.Encoded = {
|
|
20
20
|
conditions: [{ nodeType: "simple", type: "PermissionCondition", configuration: { permissionKey: "BROWSE" } }],
|
|
21
21
|
nodeType: "compound",
|
|
22
22
|
operator: "AND"
|
package/vitest.config.ts
CHANGED