@knpkv/jira-api-client 0.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.
Files changed (38) hide show
  1. package/.specs/VERSION_V3 +1 -0
  2. package/.specs/jira-v3-1001.0.0-SNAPSHOT-ea9913a8c4412d2bfb1911480b023a04544e19d8.json +55618 -0
  3. package/CHANGELOG.md +11 -0
  4. package/LICENSE +21 -0
  5. package/README.md +94 -0
  6. package/dist/JiraApiClient.d.ts +99 -0
  7. package/dist/JiraApiClient.d.ts.map +1 -0
  8. package/dist/JiraApiClient.js +94 -0
  9. package/dist/JiraApiClient.js.map +1 -0
  10. package/dist/JiraApiConfig.d.ts +57 -0
  11. package/dist/JiraApiConfig.d.ts.map +1 -0
  12. package/dist/JiraApiConfig.js +37 -0
  13. package/dist/JiraApiConfig.js.map +1 -0
  14. package/dist/OpenApiFetchClient.d.ts +55 -0
  15. package/dist/OpenApiFetchClient.d.ts.map +1 -0
  16. package/dist/OpenApiFetchClient.js +63 -0
  17. package/dist/OpenApiFetchClient.js.map +1 -0
  18. package/dist/generated/v3/index.d.ts +7 -0
  19. package/dist/generated/v3/index.d.ts.map +1 -0
  20. package/dist/generated/v3/index.js +2 -0
  21. package/dist/generated/v3/index.js.map +1 -0
  22. package/dist/generated/v3/schema.d.ts +64353 -0
  23. package/dist/index.d.ts +18 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +17 -0
  26. package/dist/index.js.map +1 -0
  27. package/package.json +78 -0
  28. package/scripts/regenerate.ts +141 -0
  29. package/src/JiraApiClient.ts +129 -0
  30. package/src/JiraApiConfig.ts +51 -0
  31. package/src/OpenApiFetchClient.ts +92 -0
  32. package/src/generated/v3/index.ts +6 -0
  33. package/src/generated/v3/schema.d.ts +64353 -0
  34. package/src/index.ts +22 -0
  35. package/test/JiraApiClient.test.ts +145 -0
  36. package/tsconfig.json +11 -0
  37. package/tsconfig.tsbuildinfo +1 -0
  38. package/vitest.config.ts +7 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ # @knpkv/jira-api-client
2
+
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#61](https://github.com/knpkv/npm/pull/61) [`fc7be8f`](https://github.com/knpkv/npm/commit/fc7be8ffaf5b6b094c7f81551e8ace6f2a8f2c4c) Thanks @konopkov! - feat: add jira-api-client and atlassian-common packages
8
+ - New @knpkv/atlassian-common: shared AST types, serializers, auth, and config
9
+ - New @knpkv/jira-api-client: Effect-based Jira REST API client (openapi-gen)
10
+ - Updated @knpkv/confluence-api-client: regenerated with openapi-gen
11
+ - Updated @knpkv/confluence-to-markdown: use new generated API client
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 knpkv
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,94 @@
1
+ # @knpkv/jira-api-client
2
+
3
+ Effect-based Jira Cloud REST API v3 client. Type-safe paths and responses generated from the official OpenAPI schema via `openapi-typescript` + `openapi-fetch`.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @knpkv/jira-api-client
9
+ ```
10
+
11
+ Peer dependencies: `effect`
12
+
13
+ ## Usage
14
+
15
+ ```typescript
16
+ import { Effect, Layer } from "effect"
17
+ import * as Redacted from "effect/Redacted"
18
+ import { JiraApiClient, JiraApiConfig, toEffect } from "@knpkv/jira-api-client"
19
+
20
+ const program = Effect.gen(function* () {
21
+ const client = yield* JiraApiClient
22
+
23
+ // Get issue by key
24
+ const issue = yield* toEffect(
25
+ client.v3.client.GET("/rest/api/3/issue/{issueIdOrKey}", {
26
+ params: { path: { issueIdOrKey: "PROJ-123" } }
27
+ })
28
+ )
29
+ console.log(issue.fields?.summary)
30
+
31
+ // Search with JQL
32
+ const results = yield* toEffect(
33
+ client.v3.client.POST("/rest/api/3/search/jql", {
34
+ body: { jql: "project = PROJ AND status != Done", maxResults: 50 }
35
+ })
36
+ )
37
+ })
38
+
39
+ // Basic auth
40
+ const configLayer = Layer.succeed(JiraApiConfig, {
41
+ baseUrl: "https://mysite.atlassian.net",
42
+ auth: {
43
+ type: "basic",
44
+ email: "user@example.com",
45
+ apiToken: Redacted.make("your-api-token")
46
+ }
47
+ })
48
+
49
+ // Or OAuth2
50
+ const oauthConfigLayer = Layer.succeed(JiraApiConfig, {
51
+ baseUrl: "",
52
+ auth: {
53
+ type: "oauth2",
54
+ accessToken: Redacted.make("oauth-access-token"),
55
+ cloudId: "your-cloud-id"
56
+ }
57
+ })
58
+
59
+ Effect.runPromise(program.pipe(Effect.provide(JiraApiClient.layer), Effect.provide(configLayer)))
60
+ ```
61
+
62
+ ## API Pattern
63
+
64
+ All API calls go through `toEffect()` which wraps the openapi-fetch promise in an Effect:
65
+
66
+ ```typescript
67
+ toEffect(client.v3.client.GET("/rest/api/3/..."))
68
+ // → Effect<ResponseData, FetchClientError>
69
+ ```
70
+
71
+ Paths are fully type-safe — autocomplete and compile-time errors for invalid paths, params, and bodies.
72
+
73
+ ## Errors
74
+
75
+ `FetchClientError` is a tagged error with `error`, `status`, and `message` fields:
76
+
77
+ ```typescript
78
+ import { FetchClientError } from "@knpkv/jira-api-client"
79
+
80
+ program.pipe(Effect.catchTag("FetchClientError", (e) => Console.log(`HTTP ${e.status}: ${e.message}`)))
81
+ ```
82
+
83
+ ## Subpath Exports
84
+
85
+ | Export | Contents |
86
+ | -------------------------------------- | ------------------------------- |
87
+ | `@knpkv/jira-api-client` | Client, config, toEffect, types |
88
+ | `@knpkv/jira-api-client/v3` | Generated V3 OpenAPI types |
89
+ | `@knpkv/jira-api-client/JiraApiClient` | Client service only |
90
+ | `@knpkv/jira-api-client/JiraApiConfig` | Config service only |
91
+
92
+ ## License
93
+
94
+ MIT
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Effect Layer wrapping openapi-fetch Jira V3 client with auth and base URL.
3
+ *
4
+ * **Mental model**
5
+ *
6
+ * - **Auth-polymorphic**: Supports both Basic (email + API token) and OAuth2 (access token +
7
+ * cloud ID) auth. The layer reads {@link JiraApiConfig} to build the Authorization header
8
+ * and derive the correct base URL.
9
+ * - **openapi-fetch wrapper**: Uses {@link OpenApiFetchClient} for Effect-based methods.
10
+ *
11
+ * **Common tasks**
12
+ *
13
+ * - Use the client: `const jira = yield* JiraApiClient; jira.v3.GET(...)`
14
+ * - Provide the layer: `Effect.provide(JiraApiClient.layer)`
15
+ *
16
+ * @module
17
+ */
18
+ import * as Context from "effect/Context";
19
+ import * as Layer from "effect/Layer";
20
+ import type { paths as V3Paths } from "./generated/v3/schema.js";
21
+ import { JiraApiConfig } from "./JiraApiConfig.js";
22
+ import { type OpenApiFetchClient } from "./OpenApiFetchClient.js";
23
+ /**
24
+ * Jira API client shape (v3 only).
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * import { toEffect } from "@knpkv/jira-api-client"
29
+ *
30
+ * // Get issue by key
31
+ * toEffect(client.v3.client.GET("/rest/api/3/issue/{issueIdOrKey}", {
32
+ * params: { path: { issueIdOrKey: "PROJ-123" } }
33
+ * }))
34
+ *
35
+ * // Search issues with JQL
36
+ * toEffect(client.v3.client.POST("/rest/api/3/search/jql", {
37
+ * body: { jql: "project = PROJ", maxResults: 50 }
38
+ * }))
39
+ * ```
40
+ *
41
+ * @category Client
42
+ */
43
+ export interface JiraApiClientShape {
44
+ readonly v3: OpenApiFetchClient<V3Paths>;
45
+ }
46
+ declare const JiraApiClient_base: Context.TagClass<JiraApiClient, "@knpkv/jira-api-client/JiraApiClient", JiraApiClientShape>;
47
+ /**
48
+ * Jira API client service.
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * import { JiraApiClient, JiraApiConfig } from "@knpkv/jira-api-client"
53
+ * import * as Redacted from "effect/Redacted"
54
+ * import * as Effect from "effect/Effect"
55
+ * import * as Layer from "effect/Layer"
56
+ *
57
+ * const program = Effect.gen(function* () {
58
+ * const client = yield* JiraApiClient
59
+ * const issue = yield* toEffect(client.v3.client.GET("/rest/api/3/issue/{issueIdOrKey}", {
60
+ * params: { path: { issueIdOrKey: "PROJ-123" } }
61
+ * }))
62
+ * console.log(issue.fields?.summary)
63
+ * })
64
+ *
65
+ * const configLayer = Layer.succeed(JiraApiConfig, {
66
+ * baseUrl: "https://mysite.atlassian.net",
67
+ * auth: {
68
+ * type: "basic",
69
+ * email: "user@example.com",
70
+ * apiToken: Redacted.make("token")
71
+ * }
72
+ * })
73
+ *
74
+ * Effect.runPromise(
75
+ * program.pipe(
76
+ * Effect.provide(JiraApiClient.layer),
77
+ * Effect.provide(configLayer)
78
+ * )
79
+ * )
80
+ * ```
81
+ *
82
+ * @category Client
83
+ */
84
+ export declare class JiraApiClient extends JiraApiClient_base {
85
+ /**
86
+ * Layer that provides JiraApiClient.
87
+ *
88
+ * Requires: JiraApiConfig
89
+ */
90
+ static readonly layer: Layer.Layer<JiraApiClient, never, JiraApiConfig>;
91
+ }
92
+ /**
93
+ * Layer that provides JiraApiClient.
94
+ *
95
+ * @category Layers
96
+ */
97
+ export declare const layer: Layer.Layer<JiraApiClient, never, JiraApiConfig>;
98
+ export {};
99
+ //# sourceMappingURL=JiraApiClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JiraApiClient.d.ts","sourceRoot":"","sources":["../src/JiraApiClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AAGzC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAErC,OAAO,KAAK,EAAE,KAAK,IAAI,OAAO,EAAE,MAAM,0BAA0B,CAAA;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAA0B,KAAK,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAEzF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,EAAE,kBAAkB,CAAC,OAAO,CAAC,CAAA;CACzC;;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,qBAAa,aAAc,SAAQ,kBAEG;IACpC;;;;OAIG;IACH,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,aAAa,EAAE,KAAK,EAAE,aAAa,CAAC,CAyBtE;CACF;AAED;;;;GAIG;AACH,eAAO,MAAM,KAAK,kDAAsB,CAAA"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Effect Layer wrapping openapi-fetch Jira V3 client with auth and base URL.
3
+ *
4
+ * **Mental model**
5
+ *
6
+ * - **Auth-polymorphic**: Supports both Basic (email + API token) and OAuth2 (access token +
7
+ * cloud ID) auth. The layer reads {@link JiraApiConfig} to build the Authorization header
8
+ * and derive the correct base URL.
9
+ * - **openapi-fetch wrapper**: Uses {@link OpenApiFetchClient} for Effect-based methods.
10
+ *
11
+ * **Common tasks**
12
+ *
13
+ * - Use the client: `const jira = yield* JiraApiClient; jira.v3.GET(...)`
14
+ * - Provide the layer: `Effect.provide(JiraApiClient.layer)`
15
+ *
16
+ * @module
17
+ */
18
+ import * as Context from "effect/Context";
19
+ import * as Effect from "effect/Effect";
20
+ import * as Encoding from "effect/Encoding";
21
+ import * as Layer from "effect/Layer";
22
+ import * as Redacted from "effect/Redacted";
23
+ import { JiraApiConfig } from "./JiraApiConfig.js";
24
+ import { makeOpenApiFetchClient } from "./OpenApiFetchClient.js";
25
+ /**
26
+ * Jira API client service.
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * import { JiraApiClient, JiraApiConfig } from "@knpkv/jira-api-client"
31
+ * import * as Redacted from "effect/Redacted"
32
+ * import * as Effect from "effect/Effect"
33
+ * import * as Layer from "effect/Layer"
34
+ *
35
+ * const program = Effect.gen(function* () {
36
+ * const client = yield* JiraApiClient
37
+ * const issue = yield* toEffect(client.v3.client.GET("/rest/api/3/issue/{issueIdOrKey}", {
38
+ * params: { path: { issueIdOrKey: "PROJ-123" } }
39
+ * }))
40
+ * console.log(issue.fields?.summary)
41
+ * })
42
+ *
43
+ * const configLayer = Layer.succeed(JiraApiConfig, {
44
+ * baseUrl: "https://mysite.atlassian.net",
45
+ * auth: {
46
+ * type: "basic",
47
+ * email: "user@example.com",
48
+ * apiToken: Redacted.make("token")
49
+ * }
50
+ * })
51
+ *
52
+ * Effect.runPromise(
53
+ * program.pipe(
54
+ * Effect.provide(JiraApiClient.layer),
55
+ * Effect.provide(configLayer)
56
+ * )
57
+ * )
58
+ * ```
59
+ *
60
+ * @category Client
61
+ */
62
+ export class JiraApiClient extends Context.Tag("@knpkv/jira-api-client/JiraApiClient")() {
63
+ /**
64
+ * Layer that provides JiraApiClient.
65
+ *
66
+ * Requires: JiraApiConfig
67
+ */
68
+ static layer = Layer.effect(JiraApiClient, Effect.gen(function* () {
69
+ const config = yield* JiraApiConfig;
70
+ // Build auth header
71
+ const authHeader = config.auth.type === "basic"
72
+ ? `Basic ${Encoding.encodeBase64(`${config.auth.email}:${Redacted.value(config.auth.apiToken)}`)}`
73
+ : `Bearer ${Redacted.value(config.auth.accessToken)}`;
74
+ // Base URL differs by auth type
75
+ const baseUrl = config.auth.type === "oauth2"
76
+ ? `https://api.atlassian.com/ex/jira/${config.auth.cloudId}`
77
+ : config.baseUrl;
78
+ const headers = {
79
+ Authorization: authHeader,
80
+ Accept: "application/json",
81
+ "Content-Type": "application/json"
82
+ };
83
+ return {
84
+ v3: makeOpenApiFetchClient(baseUrl, headers)
85
+ };
86
+ }));
87
+ }
88
+ /**
89
+ * Layer that provides JiraApiClient.
90
+ *
91
+ * @category Layers
92
+ */
93
+ export const layer = JiraApiClient.layer;
94
+ //# sourceMappingURL=JiraApiClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JiraApiClient.js","sourceRoot":"","sources":["../src/JiraApiClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AACzC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAE3C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,sBAAsB,EAA2B,MAAM,yBAAyB,CAAA;AA0BzF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,OAAO,aAAc,SAAQ,OAAO,CAAC,GAAG,CAC5C,sCAAsC,CACvC,EAAqC;IACpC;;;;OAIG;IACH,MAAM,CAAU,KAAK,GAAqD,KAAK,CAAC,MAAM,CACpF,aAAa,EACb,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,aAAa,CAAA;QAEnC,oBAAoB;QACpB,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO;YAC7C,CAAC,CAAC,SAAS,QAAQ,CAAC,YAAY,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE;YAClG,CAAC,CAAC,UAAU,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAA;QAEvD,gCAAgC;QAChC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ;YAC3C,CAAC,CAAC,qCAAqC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE;YAC5D,CAAC,CAAC,MAAM,CAAC,OAAO,CAAA;QAElB,MAAM,OAAO,GAAG;YACd,aAAa,EAAE,UAAU;YACzB,MAAM,EAAE,kBAAkB;YAC1B,cAAc,EAAE,kBAAkB;SACnC,CAAA;QAED,OAAO;YACL,EAAE,EAAE,sBAAsB,CAAU,OAAO,EAAE,OAAO,CAAC;SACtD,CAAA;IACH,CAAC,CAAC,CACH,CAAA;;AAGH;;;;GAIG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAA"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Configuration service tag for the Jira API client (basic or OAuth2 auth).
3
+ *
4
+ * **Mental model**
5
+ *
6
+ * - **Discriminated auth union**: The `auth` field is `{ type: "basic", ... } | { type: "oauth2", ... }`.
7
+ * Basic auth uses email + Redacted API token; OAuth2 uses Redacted access token + cloud ID.
8
+ * - **Base URL routing**: For OAuth2, the base URL is derived from cloud ID (`api.atlassian.com/ex/jira/{cloudId}`);
9
+ * for basic auth, `baseUrl` is used directly.
10
+ *
11
+ * @module
12
+ */
13
+ import * as Context from "effect/Context";
14
+ import type * as Redacted from "effect/Redacted";
15
+ /**
16
+ * Configuration shape for Jira API client.
17
+ *
18
+ * @category Config
19
+ */
20
+ export interface JiraApiConfigShape {
21
+ readonly baseUrl: string;
22
+ readonly auth: {
23
+ readonly type: "basic";
24
+ readonly email: string;
25
+ readonly apiToken: Redacted.Redacted<string>;
26
+ } | {
27
+ readonly type: "oauth2";
28
+ readonly accessToken: Redacted.Redacted<string>;
29
+ readonly cloudId: string;
30
+ };
31
+ }
32
+ declare const JiraApiConfig_base: Context.TagClass<JiraApiConfig, "@knpkv/jira-api-client/JiraApiConfig", JiraApiConfigShape>;
33
+ /**
34
+ * Jira API configuration service.
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * import { JiraApiConfig } from "@knpkv/jira-api-client"
39
+ * import * as Redacted from "effect/Redacted"
40
+ * import * as Layer from "effect/Layer"
41
+ *
42
+ * const configLayer = Layer.succeed(JiraApiConfig, {
43
+ * baseUrl: "https://mysite.atlassian.net",
44
+ * auth: {
45
+ * type: "basic",
46
+ * email: "user@example.com",
47
+ * apiToken: Redacted.make("token")
48
+ * }
49
+ * })
50
+ * ```
51
+ *
52
+ * @category Config
53
+ */
54
+ export declare class JiraApiConfig extends JiraApiConfig_base {
55
+ }
56
+ export {};
57
+ //# sourceMappingURL=JiraApiConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JiraApiConfig.d.ts","sourceRoot":"","sources":["../src/JiraApiConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AACzC,OAAO,KAAK,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAEhD;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,IAAI,EACT;QAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;KAAE,GAChG;QAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;QAAC,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAC3G;;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,aAAc,SAAQ,kBAEG;CAAG"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Configuration service tag for the Jira API client (basic or OAuth2 auth).
3
+ *
4
+ * **Mental model**
5
+ *
6
+ * - **Discriminated auth union**: The `auth` field is `{ type: "basic", ... } | { type: "oauth2", ... }`.
7
+ * Basic auth uses email + Redacted API token; OAuth2 uses Redacted access token + cloud ID.
8
+ * - **Base URL routing**: For OAuth2, the base URL is derived from cloud ID (`api.atlassian.com/ex/jira/{cloudId}`);
9
+ * for basic auth, `baseUrl` is used directly.
10
+ *
11
+ * @module
12
+ */
13
+ import * as Context from "effect/Context";
14
+ /**
15
+ * Jira API configuration service.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * import { JiraApiConfig } from "@knpkv/jira-api-client"
20
+ * import * as Redacted from "effect/Redacted"
21
+ * import * as Layer from "effect/Layer"
22
+ *
23
+ * const configLayer = Layer.succeed(JiraApiConfig, {
24
+ * baseUrl: "https://mysite.atlassian.net",
25
+ * auth: {
26
+ * type: "basic",
27
+ * email: "user@example.com",
28
+ * apiToken: Redacted.make("token")
29
+ * }
30
+ * })
31
+ * ```
32
+ *
33
+ * @category Config
34
+ */
35
+ export class JiraApiConfig extends Context.Tag("@knpkv/jira-api-client/JiraApiConfig")() {
36
+ }
37
+ //# sourceMappingURL=JiraApiConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JiraApiConfig.js","sourceRoot":"","sources":["../src/JiraApiConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AAezC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,OAAO,aAAc,SAAQ,OAAO,CAAC,GAAG,CAC5C,sCAAsC,CACvC,EAAqC;CAAG"}
@@ -0,0 +1,55 @@
1
+ import * as Effect from "effect/Effect";
2
+ import { type Client, type FetchResponse } from "openapi-fetch";
3
+ import type { MediaType } from "openapi-typescript-helpers";
4
+ declare const FetchClientError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
5
+ readonly _tag: "FetchClientError";
6
+ } & Readonly<A>;
7
+ /**
8
+ * Error from openapi-fetch operations.
9
+ *
10
+ * @category Errors
11
+ */
12
+ export declare class FetchClientError extends FetchClientError_base<{
13
+ readonly error: unknown;
14
+ readonly status: number;
15
+ readonly message: string;
16
+ }> {
17
+ }
18
+ /** Extract success `data` from a FetchResponse discriminated union. */
19
+ export type SuccessData<T> = T extends {
20
+ data: infer D;
21
+ error?: undefined;
22
+ } ? D : T extends {
23
+ data?: infer D;
24
+ } ? NonNullable<D> : never;
25
+ /**
26
+ * Wrap an openapi-fetch `Promise<FetchResponse>` in Effect.
27
+ *
28
+ * Extracts `data` on success, maps errors to `FetchClientError`.
29
+ * Fully type-safe — path/body constraints come from the `Client<Paths>` call site.
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * const page = yield* toEffect(client.GET("/pages/{id}", { params: { path: { id: 123 } } }))
34
+ * ```
35
+ *
36
+ * @category Utilities
37
+ */
38
+ export declare const toEffect: <T extends Record<string | number, any>, O, M extends MediaType>(promise: Promise<FetchResponse<T, O, M>>) => Effect.Effect<SuccessData<FetchResponse<T, O, M>>, FetchClientError>;
39
+ /**
40
+ * openapi-fetch client paired with the `toEffect` helper.
41
+ *
42
+ * @category Client
43
+ */
44
+ export interface OpenApiFetchClient<Paths extends {}> {
45
+ /** Type-safe openapi-fetch client. Use with `toEffect()` to get Effect. */
46
+ readonly client: Client<Paths, "application/json">;
47
+ }
48
+ /**
49
+ * Create an openapi-fetch client with auth headers pre-configured.
50
+ *
51
+ * @category Constructors
52
+ */
53
+ export declare const makeOpenApiFetchClient: <Paths extends {}>(baseUrl: string, headers: Record<string, string>) => OpenApiFetchClient<Paths>;
54
+ export {};
55
+ //# sourceMappingURL=OpenApiFetchClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OpenApiFetchClient.d.ts","sourceRoot":"","sources":["../src/OpenApiFetchClient.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAqB,EAAE,KAAK,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;;;;AAE3D;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,sBAAqC;IACzE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB,CAAC;CAAG;AAEL,uEAAuE;AACvE,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAAC,KAAK,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG,CAAC,GAC3E,CAAC,SAAS;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,WAAW,CAAC,CAAC,CAAC,GAC7C,KAAK,CAAA;AAET;;;;;;;;;;;;GAYG;AAEH,eAAO,MAAM,QAAQ,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,SAAS,EACrF,SAAS,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,KACvC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,gBAAgB,CAiBlE,CAAA;AAEJ;;;;GAIG;AACH,MAAM,WAAW,kBAAkB,CAAC,KAAK,SAAS,EAAE;IAClD,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAA;CACnD;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GAAI,KAAK,SAAS,EAAE,EACrD,SAAS,MAAM,EACf,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAC9B,kBAAkB,CAAC,KAAK,CAEzB,CAAA"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Generic Effect wrapper for openapi-fetch clients.
3
+ *
4
+ * Exposes a type-safe `Client<Paths>` and a `toEffect` helper that wraps
5
+ * any `Promise<FetchResponse>` in Effect with error mapping.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const page = yield* toEffect(client.GET("/pages/{id}", {
10
+ * params: { path: { id: 123 } }
11
+ * }))
12
+ * ```
13
+ *
14
+ * @module
15
+ */
16
+ import * as Data from "effect/Data";
17
+ import * as Effect from "effect/Effect";
18
+ import createClient, {} from "openapi-fetch";
19
+ /**
20
+ * Error from openapi-fetch operations.
21
+ *
22
+ * @category Errors
23
+ */
24
+ export class FetchClientError extends Data.TaggedError("FetchClientError") {
25
+ }
26
+ /**
27
+ * Wrap an openapi-fetch `Promise<FetchResponse>` in Effect.
28
+ *
29
+ * Extracts `data` on success, maps errors to `FetchClientError`.
30
+ * Fully type-safe — path/body constraints come from the `Client<Paths>` call site.
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * const page = yield* toEffect(client.GET("/pages/{id}", { params: { path: { id: 123 } } }))
35
+ * ```
36
+ *
37
+ * @category Utilities
38
+ */
39
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- matches FetchResponse generic constraint
40
+ export const toEffect = (promise) => Effect.tryPromise({
41
+ try: () => promise.then(({ data, error, response }) => {
42
+ if (error !== undefined || !response.ok) {
43
+ throw { error, status: response.status };
44
+ }
45
+ return data;
46
+ }),
47
+ catch: (e) => new FetchClientError({
48
+ error: e.error ?? e,
49
+ status: e.status ?? 0,
50
+ message: typeof e.error === "string"
51
+ ? e.error
52
+ : JSON.stringify(e.error ?? e)
53
+ })
54
+ });
55
+ /**
56
+ * Create an openapi-fetch client with auth headers pre-configured.
57
+ *
58
+ * @category Constructors
59
+ */
60
+ export const makeOpenApiFetchClient = (baseUrl, headers) => ({
61
+ client: createClient({ baseUrl, headers })
62
+ });
63
+ //# sourceMappingURL=OpenApiFetchClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OpenApiFetchClient.js","sourceRoot":"","sources":["../src/OpenApiFetchClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,IAAI,MAAM,aAAa,CAAA;AACnC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,YAAY,EAAE,EAAmC,MAAM,eAAe,CAAA;AAG7E;;;;GAIG;AACH,MAAM,OAAO,gBAAiB,SAAQ,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAIvE;CAAG;AAOL;;;;;;;;;;;;GAYG;AACH,0GAA0G;AAC1G,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,OAAwC,EAC8B,EAAE,CACxE,MAAM,CAAC,UAAU,CAAC;IAChB,GAAG,EAAE,GAAG,EAAE,CACR,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE;QACzC,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACxC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAA;QAC1C,CAAC;QACD,OAAO,IAA2C,CAAA;IACpD,CAAC,CAAC;IACJ,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CACX,IAAI,gBAAgB,CAAC;QACnB,KAAK,EAAG,CAA6B,CAAC,KAAK,IAAI,CAAC;QAChD,MAAM,EAAI,CAA6B,CAAC,MAA6B,IAAI,CAAC;QAC1E,OAAO,EAAE,OAAQ,CAA6B,CAAC,KAAK,KAAK,QAAQ;YAC/D,CAAC,CAAE,CAA6B,CAAC,KAAe;YAChD,CAAC,CAAC,IAAI,CAAC,SAAS,CAAE,CAA6B,CAAC,KAAK,IAAI,CAAC,CAAC;KAC9D,CAAC;CACL,CAAC,CAAA;AAYJ;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,OAAe,EACf,OAA+B,EACJ,EAAE,CAAC,CAAC;IAC/B,MAAM,EAAE,YAAY,CAA4B,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;CACtE,CAAC,CAAA"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Generated Jira Cloud REST API v3 types.
3
+ *
4
+ * @module
5
+ */
6
+ export type { components, operations, paths } from "./schema.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/generated/v3/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/generated/v3/index.ts"],"names":[],"mappings":""}