@knpkv/jira-api-client 1.1.1 → 2.1.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/CHANGELOG.md +41 -0
- package/dist/JiraApiClient.d.ts +2 -2
- package/dist/JiraApiClient.d.ts.map +1 -1
- package/dist/JiraApiClient.js +24 -11
- package/dist/JiraApiClient.js.map +1 -1
- package/dist/JiraApiConfig.d.ts +34 -10
- package/dist/JiraApiConfig.d.ts.map +1 -1
- package/dist/JiraApiConfig.js +3 -1
- package/dist/JiraApiConfig.js.map +1 -1
- package/dist/OwnOptionalKey.d.ts +13 -0
- package/dist/OwnOptionalKey.d.ts.map +1 -0
- package/dist/OwnOptionalKey.js +28 -0
- package/dist/OwnOptionalKey.js.map +1 -0
- package/dist/generated/JiraApi.d.ts +21240 -77776
- package/dist/generated/JiraApi.d.ts.map +1 -1
- package/dist/generated/JiraApi.js +2403 -2234
- package/dist/generated/JiraApi.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
- package/scripts/regenerate.ts +22 -9
- package/src/JiraApiClient.ts +41 -19
- package/src/JiraApiConfig.ts +33 -4
- package/src/OwnOptionalKey.ts +36 -0
- package/src/generated/JiraApi.ts +3277 -2894
- package/src/index.ts +3 -1
- package/test/JiraApiClient.test.ts +3 -3
- package/test/JiraApiCredential.test.ts +125 -0
- package/test/OwnOptionalKey.test.ts +24 -0
- package/test/RecursiveSchemas.test.ts +26 -0
- package/test/tsconfig.json +6 -0
- package/vitest.config.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,46 @@
|
|
|
1
1
|
# @knpkv/jira-api-client
|
|
2
2
|
|
|
3
|
+
## 2.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#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:
|
|
8
|
+
|
|
9
|
+
- `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.
|
|
10
|
+
- `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.
|
|
11
|
+
- 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.
|
|
12
|
+
- `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.
|
|
13
|
+
- `@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.
|
|
14
|
+
- `@knpkv/agent-skills`: the jcf skill names `jcf auth jira token` as the way to connect Jira.
|
|
15
|
+
|
|
16
|
+
## 2.0.0
|
|
17
|
+
|
|
18
|
+
### Major Changes
|
|
19
|
+
|
|
20
|
+
- [#438](https://github.com/knpkv/npm/pull/438) [`acb8b25`](https://github.com/knpkv/npm/commit/acb8b25772cc188a0cc1299a1b591903240cfc7c) Thanks [@github-actions](https://github.com/apps/github-actions)! - Update the generated Schema-backed Jira API client.
|
|
21
|
+
|
|
22
|
+
Breaking: these exported types now include `null`, so code that reads them must handle it: `ApprovalConfiguration`, `BoardFeaturesPayload`, `BoardsPayload`, `ConditionGroupConfiguration`, `ConditionGroupUpdate`, `CustomFieldPayload`, `FieldCapabilityPayload`, `FieldLayoutPayload`, `FieldLayoutSchemePayload`, `FieldSchemePayload`, `IssueLayoutPayload`, `IssueTypeHierarchyPayload`, `IssueTypePayload`, `IssueTypeProjectCreatePayload`, `IssueTypeScreenSchemePayload`, `NotificationSchemePayload`, `PermissionPayloadDTO`, `PreviewConditionGroupConfiguration`, `PreviewRuleConfiguration`, `ProjectId`, `RolesCapabilityPayload`, `ScopePayload`, `ScreenPayload`, `ScreenSchemePayload`, `SecuritySchemePayload`, `TargetClassification`, `TargetMandatoryFields`, `TargetStatus`, `WorkflowCapabilityPayload`, `WorkflowLayout`, `WorkflowProjectIdScope`, `WorkflowRuleConfiguration`, `WorkflowStatusLayout`, and `WorkflowTransitionLinks`. `ProjectId` and `WorkflowLayout` also appear in responses. No exports are removed; 129 are added.
|
|
23
|
+
|
|
24
|
+
### Minor Changes
|
|
25
|
+
|
|
26
|
+
- [#452](https://github.com/knpkv/npm/pull/452) [`755eafa`](https://github.com/knpkv/npm/commit/755eafab8c0bc3e82b00e2dd27c68d669a1de87e) Thanks [@konopkov](https://github.com/konopkov)! - Upgrade to Effect 4.0.0 stable. `effect` and every `@effect/*` dependency or peer dependency now require `4.0.0`; imports move from the removed `effect/unstable/*` paths to `effect/*`.
|
|
27
|
+
|
|
28
|
+
- [#376](https://github.com/knpkv/npm/pull/376) [`379b029`](https://github.com/knpkv/npm/commit/379b02947180d50d4a40cf4b7723851aa68fc183) Thanks [@konopkov](https://github.com/konopkov)! - Let a client re-read its credential per request. `JiraApiConfigContract` gains an optional
|
|
29
|
+
`resolveAuth`, and the credential union it yields is now exported as `JiraApiCredential`.
|
|
30
|
+
|
|
31
|
+
Without it, a client is pinned for life to the token that existed when its layer was built. That is
|
|
32
|
+
invisible in a command that exits in seconds and fatal in one that does not: an Atlassian access
|
|
33
|
+
token lasts about an hour, after which every request 401s and no retry inside the process can
|
|
34
|
+
recover, because the expired token is already baked into the header. `jcf watch` is meant to run all
|
|
35
|
+
day.
|
|
36
|
+
|
|
37
|
+
Omitting `resolveAuth` keeps the previous behaviour exactly — the credential in `auth` is used as
|
|
38
|
+
given, which is right for a basic-auth API token that cannot expire. When it is supplied, both the
|
|
39
|
+
`Authorization` header and the API host are derived from the same resolved value, so a resolver
|
|
40
|
+
cannot address one site while authenticating against another.
|
|
41
|
+
|
|
42
|
+
- [#452](https://github.com/knpkv/npm/pull/452) [`755eafa`](https://github.com/knpkv/npm/commit/755eafab8c0bc3e82b00e2dd27c68d669a1de87e) Thanks [@konopkov](https://github.com/konopkov)! - Decode Jira change items that omit `toString`. Effect 4.0.0 reads declared struct keys through the prototype, so an omitted `toString` resolved to `Object.prototype.toString` and failed decoding. The new `ownOptionalKey` schema treats that inherited member as an absent key.
|
|
43
|
+
|
|
3
44
|
## 1.1.1
|
|
4
45
|
|
|
5
46
|
### Patch Changes
|
package/dist/JiraApiClient.d.ts
CHANGED
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import * as Context from "effect/Context";
|
|
11
11
|
import * as Effect from "effect/Effect";
|
|
12
|
+
import * as HttpClient from "effect/http/HttpClient";
|
|
13
|
+
import type * as HttpClientError from "effect/http/HttpClientError";
|
|
12
14
|
import * as Layer from "effect/Layer";
|
|
13
15
|
import type { SchemaError } from "effect/Schema";
|
|
14
|
-
import * as HttpClient from "effect/unstable/http/HttpClient";
|
|
15
|
-
import type * as HttpClientError from "effect/unstable/http/HttpClientError";
|
|
16
16
|
import * as Generated from "./generated/JiraApi.js";
|
|
17
17
|
import { JiraApiConfig, type JiraApiConfigContract } from "./JiraApiConfig.js";
|
|
18
18
|
export interface UploadAttachmentInput {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JiraApiClient.d.ts","sourceRoot":"","sources":["../src/JiraApiClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AACzC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAGvC,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"JiraApiClient.d.ts","sourceRoot":"","sources":["../src/JiraApiClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AACzC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAGvC,OAAO,KAAK,UAAU,MAAM,wBAAwB,CAAA;AACpD,OAAO,KAAK,KAAK,eAAe,MAAM,6BAA6B,CAAA;AAGnE,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAErC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,KAAK,qBAAqB,EAA0B,MAAM,oBAAoB,CAAA;AAEtG,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACxC;AAED,MAAM,WAAW,qBAAsB,SAAQ,SAAS,CAAC,OAAO;IAC9D,QAAQ,CAAC,gBAAgB,EAAE,CACzB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,qBAAqB,KACzB,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,gBAAgB,EAAE,eAAe,CAAC,eAAe,GAAG,WAAW,CAAC,CAAA;CAC9F;AAqCD,eAAO,MAAM,IAAI,eACH,UAAU,CAAC,UAAU,UACzB,qBAAqB,KAC5B,SAAS,CAAC,OAIT,CAAA;;AAuBJ,qBAAa,aAAc,SAAQ,kBAElC;IACC,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAChC,aAAa,EACb,KAAK,EACL,aAAa,GAAG,UAAU,CAAC,UAAU,CACtC,CAQA;CACF;AAED,eAAO,MAAM,KAAK,0EAAsB,CAAA"}
|
package/dist/JiraApiClient.js
CHANGED
|
@@ -9,22 +9,35 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import * as Context from "effect/Context";
|
|
11
11
|
import * as Effect from "effect/Effect";
|
|
12
|
-
import
|
|
12
|
+
import { Base64 } from "effect/encoding";
|
|
13
13
|
import { flow } from "effect/Function";
|
|
14
|
+
import * as HttpClient from "effect/http/HttpClient";
|
|
15
|
+
import * as HttpClientRequest from "effect/http/HttpClientRequest";
|
|
16
|
+
import * as HttpClientResponse from "effect/http/HttpClientResponse";
|
|
14
17
|
import * as Layer from "effect/Layer";
|
|
15
18
|
import * as Redacted from "effect/Redacted";
|
|
16
|
-
import * as HttpClient from "effect/unstable/http/HttpClient";
|
|
17
|
-
import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest";
|
|
18
|
-
import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse";
|
|
19
19
|
import * as Generated from "./generated/JiraApi.js";
|
|
20
20
|
import { JiraApiConfig } from "./JiraApiConfig.js";
|
|
21
|
-
const authorizationHeader = (
|
|
22
|
-
? `Basic ${
|
|
23
|
-
: `Bearer ${Redacted.value(
|
|
24
|
-
const apiBaseUrl = (
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
const authorizationHeader = (auth) => auth.type === "basic"
|
|
22
|
+
? `Basic ${Base64.encode(`${auth.email}:${Redacted.value(auth.apiToken)}`)}`
|
|
23
|
+
: `Bearer ${Redacted.value(auth.accessToken)}`;
|
|
24
|
+
const apiBaseUrl = (baseUrl, auth) => auth.type === "oauth2" ? `https://api.atlassian.com/ex/jira/${auth.cloudId}` : auth.siteUrl ?? baseUrl;
|
|
25
|
+
/**
|
|
26
|
+
* Where the credential is turned into a header.
|
|
27
|
+
*
|
|
28
|
+
* Both the host and the `Authorization` header come from `auth`, so they are derived together from
|
|
29
|
+
* one value rather than separately from two reads that could disagree about which site is being
|
|
30
|
+
* addressed. When `resolveAuth` is present that pair is recomputed per request, which is the only
|
|
31
|
+
* way a token refreshed mid-run reaches the wire — `mapRequest` would capture the startup value.
|
|
32
|
+
*/
|
|
33
|
+
const addressAndAuthorize = (config) => {
|
|
34
|
+
const resolve = config.resolveAuth;
|
|
35
|
+
if (resolve === undefined) {
|
|
36
|
+
return HttpClient.mapRequest(flow(HttpClientRequest.prependUrl(apiBaseUrl(config.baseUrl, config.auth)), HttpClientRequest.setHeader("Authorization", authorizationHeader(config.auth))));
|
|
37
|
+
}
|
|
38
|
+
return HttpClient.mapRequestEffect((request) => Effect.map(resolve, (auth) => request.pipe(HttpClientRequest.prependUrl(apiBaseUrl(config.baseUrl, auth)), HttpClientRequest.setHeader("Authorization", authorizationHeader(auth)))));
|
|
39
|
+
};
|
|
40
|
+
export const make = (httpClient, config) => Generated.make(httpClient.pipe(addressAndAuthorize(config), HttpClient.mapRequest(HttpClientRequest.setHeader("Accept", "application/json"))));
|
|
28
41
|
const makeUploadAttachment = (api) => (issueIdOrKey, input) => {
|
|
29
42
|
const buffer = new ArrayBuffer(input.bytes.byteLength);
|
|
30
43
|
new Uint8Array(buffer).set(input.bytes);
|
|
@@ -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,
|
|
1
|
+
{"version":3,"file":"JiraApiClient.js","sourceRoot":"","sources":["../src/JiraApiClient.ts"],"names":[],"mappings":"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"}
|
package/dist/JiraApiConfig.d.ts
CHANGED
|
@@ -6,12 +6,30 @@
|
|
|
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
|
+
* - **`auth` is a snapshot; `resolveAuth` is a subscription.** A credential that can expire needs the
|
|
11
|
+
* second one — see its own note.
|
|
10
12
|
*
|
|
11
13
|
* @module
|
|
12
14
|
*/
|
|
13
15
|
import * as Context from "effect/Context";
|
|
16
|
+
import type * as Effect from "effect/Effect";
|
|
14
17
|
import type * as Redacted from "effect/Redacted";
|
|
18
|
+
/** How a request proves who is asking. */
|
|
19
|
+
export type JiraApiCredential = {
|
|
20
|
+
readonly type: "basic";
|
|
21
|
+
readonly email: string;
|
|
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;
|
|
28
|
+
} | {
|
|
29
|
+
readonly type: "oauth2";
|
|
30
|
+
readonly accessToken: Redacted.Redacted<string>;
|
|
31
|
+
readonly cloudId: string;
|
|
32
|
+
};
|
|
15
33
|
/**
|
|
16
34
|
* Configuration shape for Jira API client.
|
|
17
35
|
*
|
|
@@ -19,15 +37,21 @@ import type * as Redacted from "effect/Redacted";
|
|
|
19
37
|
*/
|
|
20
38
|
export interface JiraApiConfigContract {
|
|
21
39
|
readonly baseUrl: string;
|
|
22
|
-
readonly auth:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
40
|
+
readonly auth: JiraApiCredential;
|
|
41
|
+
/**
|
|
42
|
+
* Re-read before every request, when supplied. Otherwise `auth` is used as given.
|
|
43
|
+
*
|
|
44
|
+
* A `Redacted` token is a value, so a client built from one is pinned to it for as long as the
|
|
45
|
+
* client lives. That is invisible in a command that exits in seconds and fatal in one that does
|
|
46
|
+
* not: an Atlassian access token lasts about an hour, after which every request 401s and no amount
|
|
47
|
+
* of retrying inside the process can recover, because the expired token is baked into the header.
|
|
48
|
+
* `jcf watch` is meant to run all day, so it supplies this and a refresh reaches the next request.
|
|
49
|
+
*
|
|
50
|
+
* Typed as infallible on purpose. This runs inside request preprocessing, where a new error would
|
|
51
|
+
* widen every operation's error channel; a resolver that cannot read its credential yields
|
|
52
|
+
* whatever it has, and the 401 that follows is the same one an absent login already produces.
|
|
53
|
+
*/
|
|
54
|
+
readonly resolveAuth?: Effect.Effect<JiraApiCredential> | undefined;
|
|
31
55
|
}
|
|
32
56
|
declare const JiraApiConfig_base: Context.ServiceClass<JiraApiConfig, "@knpkv/jira-api-client/JiraApiConfig", JiraApiConfigContract>;
|
|
33
57
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JiraApiConfig.d.ts","sourceRoot":"","sources":["../src/JiraApiConfig.ts"],"names":[],"mappings":"AAAA
|
|
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,9 @@
|
|
|
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
|
+
* - **`auth` is a snapshot; `resolveAuth` is a subscription.** A credential that can expire needs the
|
|
11
|
+
* second one — see its own note.
|
|
10
12
|
*
|
|
11
13
|
* @module
|
|
12
14
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JiraApiConfig.js","sourceRoot":"","sources":["../src/JiraApiConfig.ts"],"names":[],"mappings":"AAAA
|
|
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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as Schema from "effect/Schema";
|
|
2
|
+
/** `Object.prototype` members that Jira payloads use as ordinary field names. */
|
|
3
|
+
export type PrototypeKey = "toString";
|
|
4
|
+
/**
|
|
5
|
+
* Optional key for a field named after an `Object.prototype` member, such as Jira's `toString`.
|
|
6
|
+
*
|
|
7
|
+
* Effect resolves declared struct keys with `in`, so a JSON object that omits `toString` presents the inherited
|
|
8
|
+
* `Object.prototype.toString`. Only that exact inherited function decodes as an absent key; any other value must
|
|
9
|
+
* satisfy `schema`. Use it in place of `Schema.optionalKey(schema)` for these keys; the encoded and decoded types
|
|
10
|
+
* stay those of `Schema.optionalKey(schema)`.
|
|
11
|
+
*/
|
|
12
|
+
export declare const ownOptionalKey: <S extends Schema.Top>(key: PrototypeKey, schema: S) => Schema.decodeTo<Schema.optionalKey<Schema.toType<S>>, Schema.optionalKey<Schema.Union<readonly [S, Schema.declare<never, never>]>>, never, never>;
|
|
13
|
+
//# sourceMappingURL=OwnOptionalKey.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OwnOptionalKey.d.ts","sourceRoot":"","sources":["../src/OwnOptionalKey.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAGvC,iFAAiF;AACjF,MAAM,MAAM,YAAY,GAAG,UAAU,CAAA;AAErC;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,MAAM,CAAC,GAAG,OAAO,YAAY,UAAU,CAAC,sJAchF,CAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional struct keys that shadow `Object.prototype` members.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
import * as Option from "effect/Option";
|
|
7
|
+
import * as Predicate from "effect/Predicate";
|
|
8
|
+
import * as Schema from "effect/Schema";
|
|
9
|
+
import * as SchemaGetter from "effect/SchemaGetter";
|
|
10
|
+
/**
|
|
11
|
+
* Optional key for a field named after an `Object.prototype` member, such as Jira's `toString`.
|
|
12
|
+
*
|
|
13
|
+
* Effect resolves declared struct keys with `in`, so a JSON object that omits `toString` presents the inherited
|
|
14
|
+
* `Object.prototype.toString`. Only that exact inherited function decodes as an absent key; any other value must
|
|
15
|
+
* satisfy `schema`. Use it in place of `Schema.optionalKey(schema)` for these keys; the encoded and decoded types
|
|
16
|
+
* stay those of `Schema.optionalKey(schema)`.
|
|
17
|
+
*/
|
|
18
|
+
export const ownOptionalKey = (key, schema) => {
|
|
19
|
+
const inherited = Object.prototype[key];
|
|
20
|
+
// Typed `never`: the inherited member is not a domain value and never survives decoding.
|
|
21
|
+
const isInherited = Predicate.compose(Predicate.isFunction, (member) => member === inherited);
|
|
22
|
+
const InheritedMember = Schema.declare(isInherited, { expected: `the inherited Object.prototype.${key}` });
|
|
23
|
+
return Schema.optionalKey(Schema.Union([schema, InheritedMember])).pipe(Schema.decodeTo(Schema.optionalKey(Schema.toType(schema)), {
|
|
24
|
+
decode: SchemaGetter.transformOptional(Option.filter(Predicate.not(isInherited))),
|
|
25
|
+
encode: SchemaGetter.passthrough()
|
|
26
|
+
}));
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=OwnOptionalKey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OwnOptionalKey.js","sourceRoot":"","sources":["../src/OwnOptionalKey.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,SAAS,MAAM,kBAAkB,CAAA;AAC7C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,YAAY,MAAM,qBAAqB,CAAA;AAKnD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAuB,GAAiB,EAAE,MAAS,EAAE,EAAE;IACnF,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;IACvC,yFAAyF;IACzF,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,CACnC,SAAS,CAAC,UAAU,EACpB,CAAC,MAAgB,EAAmB,EAAE,CAAC,MAAM,KAAK,SAAS,CAC5D,CAAA;IACD,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,kCAAkC,GAAG,EAAE,EAAE,CAAC,CAAA;IAC1G,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI,CACrE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE;QACzD,MAAM,EAAE,YAAY,CAAC,iBAAiB,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;QACjF,MAAM,EAAE,YAAY,CAAC,WAAW,EAAE;KACnC,CAAC,CACH,CAAA;AACH,CAAC,CAAA"}
|