@knpkv/atlassian-common 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.
- package/CHANGELOG.md +11 -0
- package/LICENSE +21 -0
- package/README.md +107 -0
- package/dist/Brand.d.ts +118 -0
- package/dist/Brand.d.ts.map +1 -0
- package/dist/Brand.js +107 -0
- package/dist/Brand.js.map +1 -0
- package/dist/Hash.d.ts +53 -0
- package/dist/Hash.d.ts.map +1 -0
- package/dist/Hash.js +63 -0
- package/dist/Hash.js.map +1 -0
- package/dist/SerializeError.d.ts +48 -0
- package/dist/SerializeError.d.ts.map +1 -0
- package/dist/SerializeError.js +42 -0
- package/dist/SerializeError.js.map +1 -0
- package/dist/ast/BlockNode.d.ts +429 -0
- package/dist/ast/BlockNode.d.ts.map +1 -0
- package/dist/ast/BlockNode.js +279 -0
- package/dist/ast/BlockNode.js.map +1 -0
- package/dist/ast/Document.d.ts +255 -0
- package/dist/ast/Document.d.ts.map +1 -0
- package/dist/ast/Document.js +80 -0
- package/dist/ast/Document.js.map +1 -0
- package/dist/ast/InlineNode.d.ts +483 -0
- package/dist/ast/InlineNode.d.ts.map +1 -0
- package/dist/ast/InlineNode.js +268 -0
- package/dist/ast/InlineNode.js.map +1 -0
- package/dist/ast/MacroNode.d.ts +214 -0
- package/dist/ast/MacroNode.d.ts.map +1 -0
- package/dist/ast/MacroNode.js +110 -0
- package/dist/ast/MacroNode.js.map +1 -0
- package/dist/ast/index.d.ts +10 -0
- package/dist/ast/index.d.ts.map +1 -0
- package/dist/ast/index.js +14 -0
- package/dist/ast/index.js.map +1 -0
- package/dist/auth/OAuthEndpoints.d.ts +95 -0
- package/dist/auth/OAuthEndpoints.d.ts.map +1 -0
- package/dist/auth/OAuthEndpoints.js +112 -0
- package/dist/auth/OAuthEndpoints.js.map +1 -0
- package/dist/auth/OAuthErrors.d.ts +76 -0
- package/dist/auth/OAuthErrors.d.ts.map +1 -0
- package/dist/auth/OAuthErrors.js +85 -0
- package/dist/auth/OAuthErrors.js.map +1 -0
- package/dist/auth/OAuthOperations.d.ts +87 -0
- package/dist/auth/OAuthOperations.d.ts.map +1 -0
- package/dist/auth/OAuthOperations.js +169 -0
- package/dist/auth/OAuthOperations.js.map +1 -0
- package/dist/auth/OAuthResponseSchemas.d.ts +65 -0
- package/dist/auth/OAuthResponseSchemas.d.ts.map +1 -0
- package/dist/auth/OAuthResponseSchemas.js +47 -0
- package/dist/auth/OAuthResponseSchemas.js.map +1 -0
- package/dist/auth/index.d.ts +11 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +16 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/uuid.d.ts +14 -0
- package/dist/auth/uuid.d.ts.map +1 -0
- package/dist/auth/uuid.js +14 -0
- package/dist/auth/uuid.js.map +1 -0
- package/dist/config/ConfigPaths.d.ts +95 -0
- package/dist/config/ConfigPaths.d.ts.map +1 -0
- package/dist/config/ConfigPaths.js +102 -0
- package/dist/config/ConfigPaths.js.map +1 -0
- package/dist/config/OAuthSchemas.d.ts +144 -0
- package/dist/config/OAuthSchemas.d.ts.map +1 -0
- package/dist/config/OAuthSchemas.js +107 -0
- package/dist/config/OAuthSchemas.js.map +1 -0
- package/dist/config/TokenStorage.d.ts +96 -0
- package/dist/config/TokenStorage.d.ts.map +1 -0
- package/dist/config/TokenStorage.js +128 -0
- package/dist/config/TokenStorage.js.map +1 -0
- package/dist/config/index.d.ts +9 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +12 -0
- package/dist/config/index.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/index.d.ts +7 -0
- package/dist/parsers/index.d.ts.map +1 -0
- package/dist/parsers/index.js +8 -0
- package/dist/parsers/index.js.map +1 -0
- package/dist/serializers/MarkdownSerializer.d.ts +63 -0
- package/dist/serializers/MarkdownSerializer.d.ts.map +1 -0
- package/dist/serializers/MarkdownSerializer.js +367 -0
- package/dist/serializers/MarkdownSerializer.js.map +1 -0
- package/dist/serializers/index.d.ts +7 -0
- package/dist/serializers/index.d.ts.map +1 -0
- package/dist/serializers/index.js +7 -0
- package/dist/serializers/index.js.map +1 -0
- package/package.json +86 -0
- package/src/Brand.ts +142 -0
- package/src/Hash.ts +68 -0
- package/src/SerializeError.ts +50 -0
- package/src/ast/BlockNode.ts +386 -0
- package/src/ast/Document.ts +101 -0
- package/src/ast/InlineNode.ts +328 -0
- package/src/ast/MacroNode.ts +172 -0
- package/src/ast/index.ts +87 -0
- package/src/auth/OAuthEndpoints.ts +142 -0
- package/src/auth/OAuthErrors.ts +101 -0
- package/src/auth/OAuthOperations.ts +276 -0
- package/src/auth/OAuthResponseSchemas.ts +70 -0
- package/src/auth/index.ts +47 -0
- package/src/auth/uuid.ts +14 -0
- package/src/config/ConfigPaths.ts +179 -0
- package/src/config/OAuthSchemas.ts +146 -0
- package/src/config/TokenStorage.ts +228 -0
- package/src/config/index.ts +43 -0
- package/src/index.ts +34 -0
- package/src/parsers/index.ts +8 -0
- package/src/serializers/MarkdownSerializer.ts +498 -0
- package/src/serializers/index.ts +7 -0
- package/test/Brand.test.ts +90 -0
- package/test/MarkdownSerializer.test.ts +82 -0
- package/test/OAuthEndpoints.test.ts +109 -0
- package/test/OAuthOperations.test.ts +315 -0
- package/tsconfig.json +11 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/vitest.config.ts +12 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# @knpkv/atlassian-common
|
|
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,107 @@
|
|
|
1
|
+
# @knpkv/atlassian-common
|
|
2
|
+
|
|
3
|
+
Shared utilities for Atlassian tools: OAuth2 + PKCE auth, token storage, config paths, AST types, and markdown serialization.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @knpkv/atlassian-common
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Subpath Exports
|
|
12
|
+
|
|
13
|
+
| Export | Contents |
|
|
14
|
+
| ------------------------------------- | -------------------------------------------- |
|
|
15
|
+
| `@knpkv/atlassian-common` | Everything (AST, auth, config, serializers) |
|
|
16
|
+
| `@knpkv/atlassian-common/ast` | Inline, block, macro, and document AST nodes |
|
|
17
|
+
| `@knpkv/atlassian-common/auth` | OAuth2 endpoints, PKCE, token exchange |
|
|
18
|
+
| `@knpkv/atlassian-common/config` | Config paths, schemas, token storage |
|
|
19
|
+
| `@knpkv/atlassian-common/serializers` | Markdown serializer for AST nodes |
|
|
20
|
+
|
|
21
|
+
## OAuth2 + PKCE
|
|
22
|
+
|
|
23
|
+
Uses Web Crypto API (`globalThis.crypto`) — no `node:crypto` dependency. PKCE code verifier/challenge use `effect/Encoding` for base64url.
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { Effect } from "effect"
|
|
27
|
+
import {
|
|
28
|
+
generateCodeVerifier,
|
|
29
|
+
computeCodeChallenge,
|
|
30
|
+
buildAuthUrl,
|
|
31
|
+
exchangeCodeForTokens,
|
|
32
|
+
JIRA_SCOPES
|
|
33
|
+
} from "@knpkv/atlassian-common/auth"
|
|
34
|
+
|
|
35
|
+
const program = Effect.gen(function* () {
|
|
36
|
+
// 1. Generate PKCE pair
|
|
37
|
+
const codeVerifier = generateCodeVerifier()
|
|
38
|
+
const codeChallenge = yield* computeCodeChallenge(codeVerifier)
|
|
39
|
+
|
|
40
|
+
// 2. Build authorization URL
|
|
41
|
+
const url = buildAuthUrl({
|
|
42
|
+
clientId: "your-client-id",
|
|
43
|
+
state: "random-csrf-token",
|
|
44
|
+
port: 8585,
|
|
45
|
+
scopes: JIRA_SCOPES,
|
|
46
|
+
codeChallenge
|
|
47
|
+
})
|
|
48
|
+
// → redirect user to `url`
|
|
49
|
+
|
|
50
|
+
// 3. Exchange code for tokens (after callback)
|
|
51
|
+
const tokens = yield* exchangeCodeForTokens({
|
|
52
|
+
clientId: "your-client-id",
|
|
53
|
+
clientSecret: "your-client-secret",
|
|
54
|
+
code: "auth-code-from-callback",
|
|
55
|
+
redirectUri: "http://localhost:8585/callback",
|
|
56
|
+
codeVerifier
|
|
57
|
+
})
|
|
58
|
+
// tokens.access_token, tokens.refresh_token, tokens.expires_in
|
|
59
|
+
})
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Token Storage
|
|
63
|
+
|
|
64
|
+
Stores OAuth config and tokens in `~/.config/atlassian/` with 0600 permissions.
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { Effect } from "effect"
|
|
68
|
+
import {
|
|
69
|
+
saveToken,
|
|
70
|
+
loadToken,
|
|
71
|
+
isTokenExpired,
|
|
72
|
+
saveOAuthConfig,
|
|
73
|
+
loadOAuthConfig,
|
|
74
|
+
HomeDirectoryLive
|
|
75
|
+
} from "@knpkv/atlassian-common/config"
|
|
76
|
+
|
|
77
|
+
const program = Effect.gen(function* () {
|
|
78
|
+
yield* saveOAuthConfig({ clientId: "...", clientSecret: "..." }, "jira")
|
|
79
|
+
const config = yield* loadOAuthConfig("jira")
|
|
80
|
+
|
|
81
|
+
yield* saveToken({ access_token: "...", refresh_token: "...", expires_in: 3600 }, "jira")
|
|
82
|
+
const token = yield* loadToken("jira")
|
|
83
|
+
const expired = isTokenExpired(token)
|
|
84
|
+
}).pipe(Effect.provide(HomeDirectoryLive))
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## AST Types
|
|
88
|
+
|
|
89
|
+
Typed Atlassian Document Format nodes — used by `@knpkv/jira-cli` and `@knpkv/confluence-to-markdown`.
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { Document, Paragraph, Text, Heading, CodeBlock } from "@knpkv/atlassian-common/ast"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Markdown Serializer
|
|
96
|
+
|
|
97
|
+
Converts AST nodes to markdown strings.
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
import { serializeToMarkdown } from "@knpkv/atlassian-common/serializers"
|
|
101
|
+
|
|
102
|
+
const markdown = serializeToMarkdown(document)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
MIT
|
package/dist/Brand.d.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Branded string types for type-safe Atlassian domain values.
|
|
3
|
+
*
|
|
4
|
+
* **Mental model**
|
|
5
|
+
*
|
|
6
|
+
* - **Brand = runtime validation + compile-time narrowing**: Each brand combines
|
|
7
|
+
* an Effect `Brand.refined` (throws on invalid values) with an Effect `Schema`
|
|
8
|
+
* (composable validation). The `Type` property exposes the branded type for use
|
|
9
|
+
* in type annotations.
|
|
10
|
+
* - **Pattern-guarded strings**: `SpaceKey`, `IssueKey`, `ProjectKey` are regex-branded;
|
|
11
|
+
* `PageId` is non-empty branded; `ContentHash` is SHA256 hex branded.
|
|
12
|
+
*
|
|
13
|
+
* **Common tasks**
|
|
14
|
+
*
|
|
15
|
+
* - Create a custom brand: {@link makeBrandedString}, {@link makeBrandedNonEmptyString}
|
|
16
|
+
* - Validate a Jira ticket key: {@link IssueKey}
|
|
17
|
+
* - Validate a content hash: {@link ContentHash}
|
|
18
|
+
*
|
|
19
|
+
* **Gotchas**
|
|
20
|
+
*
|
|
21
|
+
* - Brand constructors throw synchronously on invalid input — wrap in `Effect.try` if
|
|
22
|
+
* the input is untrusted.
|
|
23
|
+
*
|
|
24
|
+
* @module
|
|
25
|
+
*/
|
|
26
|
+
import * as Brand from "effect/Brand";
|
|
27
|
+
import * as Schema from "effect/Schema";
|
|
28
|
+
/**
|
|
29
|
+
* Create a branded string type with pattern validation.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* import { makeBrandedString } from "@knpkv/atlassian-common"
|
|
34
|
+
*
|
|
35
|
+
* const IssueKey = makeBrandedString("IssueKey", /^[A-Z]+-\d+$/)
|
|
36
|
+
* type IssueKey = typeof IssueKey.Type
|
|
37
|
+
*
|
|
38
|
+
* const key = IssueKey("PROJ-123") // OK
|
|
39
|
+
* const bad = IssueKey("invalid") // Throws
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @category Brand
|
|
43
|
+
*/
|
|
44
|
+
export declare const makeBrandedString: <B extends string>(name: B, pattern: RegExp) => Brand.Brand.Constructor<string & Brand.Brand<B>> & {
|
|
45
|
+
schema: Schema.brand<Schema.filter<typeof Schema.String>, B>;
|
|
46
|
+
Type: string & Brand.Brand<B>;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Create a branded non-empty string type.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* import { makeBrandedNonEmptyString } from "@knpkv/atlassian-common"
|
|
54
|
+
*
|
|
55
|
+
* const PageId = makeBrandedNonEmptyString("PageId")
|
|
56
|
+
* type PageId = typeof PageId.Type
|
|
57
|
+
*
|
|
58
|
+
* const id = PageId("12345") // OK
|
|
59
|
+
* const bad = PageId("") // Throws
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @category Brand
|
|
63
|
+
*/
|
|
64
|
+
export declare const makeBrandedNonEmptyString: <B extends string>(name: B) => Brand.Brand.Constructor<string & Brand.Brand<B>> & {
|
|
65
|
+
schema: Schema.brand<Schema.filter<typeof Schema.String>, B>;
|
|
66
|
+
Type: string & Brand.Brand<B>;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Confluence Page ID (non-empty string).
|
|
70
|
+
*
|
|
71
|
+
* @category Brand
|
|
72
|
+
*/
|
|
73
|
+
export declare const PageId: Brand.Brand.Constructor<string & Brand.Brand<"PageId">> & {
|
|
74
|
+
schema: Schema.brand<Schema.filter<typeof Schema.String>, "PageId">;
|
|
75
|
+
Type: string & Brand.Brand<"PageId">;
|
|
76
|
+
};
|
|
77
|
+
export type PageId = typeof PageId.Type;
|
|
78
|
+
/**
|
|
79
|
+
* Confluence Space Key (uppercase alphanumeric).
|
|
80
|
+
*
|
|
81
|
+
* @category Brand
|
|
82
|
+
*/
|
|
83
|
+
export declare const SpaceKey: Brand.Brand.Constructor<string & Brand.Brand<"SpaceKey">> & {
|
|
84
|
+
schema: Schema.brand<Schema.filter<typeof Schema.String>, "SpaceKey">;
|
|
85
|
+
Type: string & Brand.Brand<"SpaceKey">;
|
|
86
|
+
};
|
|
87
|
+
export type SpaceKey = typeof SpaceKey.Type;
|
|
88
|
+
/**
|
|
89
|
+
* Jira Issue Key (PROJECT-123 format).
|
|
90
|
+
*
|
|
91
|
+
* @category Brand
|
|
92
|
+
*/
|
|
93
|
+
export declare const IssueKey: Brand.Brand.Constructor<string & Brand.Brand<"IssueKey">> & {
|
|
94
|
+
schema: Schema.brand<Schema.filter<typeof Schema.String>, "IssueKey">;
|
|
95
|
+
Type: string & Brand.Brand<"IssueKey">;
|
|
96
|
+
};
|
|
97
|
+
export type IssueKey = typeof IssueKey.Type;
|
|
98
|
+
/**
|
|
99
|
+
* Jira Project Key (uppercase alphanumeric).
|
|
100
|
+
*
|
|
101
|
+
* @category Brand
|
|
102
|
+
*/
|
|
103
|
+
export declare const ProjectKey: Brand.Brand.Constructor<string & Brand.Brand<"ProjectKey">> & {
|
|
104
|
+
schema: Schema.brand<Schema.filter<typeof Schema.String>, "ProjectKey">;
|
|
105
|
+
Type: string & Brand.Brand<"ProjectKey">;
|
|
106
|
+
};
|
|
107
|
+
export type ProjectKey = typeof ProjectKey.Type;
|
|
108
|
+
/**
|
|
109
|
+
* Content hash (SHA256 hex string).
|
|
110
|
+
*
|
|
111
|
+
* @category Brand
|
|
112
|
+
*/
|
|
113
|
+
export declare const ContentHash: Brand.Brand.Constructor<string & Brand.Brand<"ContentHash">> & {
|
|
114
|
+
schema: Schema.brand<Schema.filter<typeof Schema.String>, "ContentHash">;
|
|
115
|
+
Type: string & Brand.Brand<"ContentHash">;
|
|
116
|
+
};
|
|
117
|
+
export type ContentHash = typeof ContentHash.Type;
|
|
118
|
+
//# sourceMappingURL=Brand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Brand.d.ts","sourceRoot":"","sources":["../src/Brand.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,MAAM,EAChD,MAAM,CAAC,EACP,SAAS,MAAM;;;CAkBhB,CAAA;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,yBAAyB,GAAI,CAAC,SAAS,MAAM,EAAE,MAAM,CAAC;;;CAiBlE,CAAA;AAID;;;;GAIG;AACH,eAAO,MAAM,MAAM;;;CAAsC,CAAA;AACzD,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AAEvC;;;;GAIG;AACH,eAAO,MAAM,QAAQ;;;CAAoD,CAAA;AACzE,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAA;AAE3C;;;;GAIG;AACH,eAAO,MAAM,QAAQ;;;CAAwD,CAAA;AAC7E,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAA;AAE3C;;;;GAIG;AACH,eAAO,MAAM,UAAU;;;CAAsD,CAAA;AAC7E,MAAM,MAAM,UAAU,GAAG,OAAO,UAAU,CAAC,IAAI,CAAA;AAE/C;;;;GAIG;AACH,eAAO,MAAM,WAAW;;;CAAqD,CAAA;AAC7E,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC,IAAI,CAAA"}
|
package/dist/Brand.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Branded string types for type-safe Atlassian domain values.
|
|
3
|
+
*
|
|
4
|
+
* **Mental model**
|
|
5
|
+
*
|
|
6
|
+
* - **Brand = runtime validation + compile-time narrowing**: Each brand combines
|
|
7
|
+
* an Effect `Brand.refined` (throws on invalid values) with an Effect `Schema`
|
|
8
|
+
* (composable validation). The `Type` property exposes the branded type for use
|
|
9
|
+
* in type annotations.
|
|
10
|
+
* - **Pattern-guarded strings**: `SpaceKey`, `IssueKey`, `ProjectKey` are regex-branded;
|
|
11
|
+
* `PageId` is non-empty branded; `ContentHash` is SHA256 hex branded.
|
|
12
|
+
*
|
|
13
|
+
* **Common tasks**
|
|
14
|
+
*
|
|
15
|
+
* - Create a custom brand: {@link makeBrandedString}, {@link makeBrandedNonEmptyString}
|
|
16
|
+
* - Validate a Jira ticket key: {@link IssueKey}
|
|
17
|
+
* - Validate a content hash: {@link ContentHash}
|
|
18
|
+
*
|
|
19
|
+
* **Gotchas**
|
|
20
|
+
*
|
|
21
|
+
* - Brand constructors throw synchronously on invalid input — wrap in `Effect.try` if
|
|
22
|
+
* the input is untrusted.
|
|
23
|
+
*
|
|
24
|
+
* @module
|
|
25
|
+
*/
|
|
26
|
+
import * as Brand from "effect/Brand";
|
|
27
|
+
import * as Schema from "effect/Schema";
|
|
28
|
+
/**
|
|
29
|
+
* Create a branded string type with pattern validation.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* import { makeBrandedString } from "@knpkv/atlassian-common"
|
|
34
|
+
*
|
|
35
|
+
* const IssueKey = makeBrandedString("IssueKey", /^[A-Z]+-\d+$/)
|
|
36
|
+
* type IssueKey = typeof IssueKey.Type
|
|
37
|
+
*
|
|
38
|
+
* const key = IssueKey("PROJ-123") // OK
|
|
39
|
+
* const bad = IssueKey("invalid") // Throws
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @category Brand
|
|
43
|
+
*/
|
|
44
|
+
export const makeBrandedString = (name, pattern) => {
|
|
45
|
+
const brand = Brand.refined((s) => pattern.test(s), (s) => Brand.error(`Invalid ${name}: ${s} does not match ${pattern}`));
|
|
46
|
+
const schema = Schema.String.pipe(Schema.pattern(pattern), Schema.brand(name));
|
|
47
|
+
return Object.assign(brand, {
|
|
48
|
+
schema,
|
|
49
|
+
Type: undefined
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Create a branded non-empty string type.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* import { makeBrandedNonEmptyString } from "@knpkv/atlassian-common"
|
|
58
|
+
*
|
|
59
|
+
* const PageId = makeBrandedNonEmptyString("PageId")
|
|
60
|
+
* type PageId = typeof PageId.Type
|
|
61
|
+
*
|
|
62
|
+
* const id = PageId("12345") // OK
|
|
63
|
+
* const bad = PageId("") // Throws
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* @category Brand
|
|
67
|
+
*/
|
|
68
|
+
export const makeBrandedNonEmptyString = (name) => {
|
|
69
|
+
const brand = Brand.refined((s) => s.length > 0, (_s) => Brand.error(`${name} cannot be empty`));
|
|
70
|
+
const schema = Schema.String.pipe(Schema.nonEmptyString(), Schema.brand(name));
|
|
71
|
+
return Object.assign(brand, {
|
|
72
|
+
schema,
|
|
73
|
+
Type: undefined
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
// Common branded types for Atlassian products
|
|
77
|
+
/**
|
|
78
|
+
* Confluence Page ID (non-empty string).
|
|
79
|
+
*
|
|
80
|
+
* @category Brand
|
|
81
|
+
*/
|
|
82
|
+
export const PageId = makeBrandedNonEmptyString("PageId");
|
|
83
|
+
/**
|
|
84
|
+
* Confluence Space Key (uppercase alphanumeric).
|
|
85
|
+
*
|
|
86
|
+
* @category Brand
|
|
87
|
+
*/
|
|
88
|
+
export const SpaceKey = makeBrandedString("SpaceKey", /^[A-Z][A-Z0-9]*$/);
|
|
89
|
+
/**
|
|
90
|
+
* Jira Issue Key (PROJECT-123 format).
|
|
91
|
+
*
|
|
92
|
+
* @category Brand
|
|
93
|
+
*/
|
|
94
|
+
export const IssueKey = makeBrandedString("IssueKey", /^[A-Z][A-Z0-9]*-\d+$/);
|
|
95
|
+
/**
|
|
96
|
+
* Jira Project Key (uppercase alphanumeric).
|
|
97
|
+
*
|
|
98
|
+
* @category Brand
|
|
99
|
+
*/
|
|
100
|
+
export const ProjectKey = makeBrandedString("ProjectKey", /^[A-Z][A-Z0-9]*$/);
|
|
101
|
+
/**
|
|
102
|
+
* Content hash (SHA256 hex string).
|
|
103
|
+
*
|
|
104
|
+
* @category Brand
|
|
105
|
+
*/
|
|
106
|
+
export const ContentHash = makeBrandedString("ContentHash", /^[a-f0-9]{64}$/);
|
|
107
|
+
//# sourceMappingURL=Brand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Brand.js","sourceRoot":"","sources":["../src/Brand.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,IAAO,EACP,OAAe,EACf,EAAE;IAGF,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CACzB,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EACtB,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,mBAAmB,OAAO,EAAE,CAAC,CACtE,CAAA;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAC/B,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EACvB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CACnB,CAAA;IAED,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE;QAC1B,MAAM;QACN,IAAI,EAAE,SAAmC;KAC1C,CAAC,CAAA;AACJ,CAAC,CAAA;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAmB,IAAO,EAAE,EAAE;IAGrE,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CACzB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,EACnB,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,IAAI,kBAAkB,CAAC,CAC/C,CAAA;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAC/B,MAAM,CAAC,cAAc,EAAE,EACvB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CACnB,CAAA;IAED,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE;QAC1B,MAAM;QACN,IAAI,EAAE,SAAmC;KAC1C,CAAC,CAAA;AACJ,CAAC,CAAA;AAED,8CAA8C;AAE9C;;;;GAIG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,yBAAyB,CAAC,QAAQ,CAAC,CAAA;AAGzD;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAA;AAGzE;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,UAAU,EAAE,sBAAsB,CAAC,CAAA;AAG7E;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,iBAAiB,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAA;AAG7E;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,iBAAiB,CAAC,aAAa,EAAE,gBAAgB,CAAC,CAAA"}
|
package/dist/Hash.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SHA256 content hashing via Node.js crypto, returning branded {@link ContentHash} values.
|
|
3
|
+
*
|
|
4
|
+
* **Mental model**
|
|
5
|
+
*
|
|
6
|
+
* - **Effect-wrapped crypto**: {@link hashContent} and {@link hashBuffer} return
|
|
7
|
+
* `Effect<ContentHash>` so hashing composes into pipelines without try/catch.
|
|
8
|
+
* - **Sync escape hatch**: {@link hashContentSync} for contexts where Effect isn't needed.
|
|
9
|
+
*
|
|
10
|
+
* **Common tasks**
|
|
11
|
+
*
|
|
12
|
+
* - Hash a string: {@link hashContent}
|
|
13
|
+
* - Hash a buffer: {@link hashBuffer}
|
|
14
|
+
* - Compare hashes: {@link hashEquals}
|
|
15
|
+
*
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
import * as Effect from "effect/Effect";
|
|
19
|
+
import { ContentHash } from "./Brand.js";
|
|
20
|
+
/**
|
|
21
|
+
* Compute SHA256 hash of a string.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* import { hashContent } from "@knpkv/atlassian-common"
|
|
26
|
+
* import * as Effect from "effect/Effect"
|
|
27
|
+
*
|
|
28
|
+
* const hash = Effect.runSync(hashContent("hello world"))
|
|
29
|
+
* // => "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @category Hash
|
|
33
|
+
*/
|
|
34
|
+
export declare const hashContent: (content: string) => Effect.Effect<ContentHash>;
|
|
35
|
+
/**
|
|
36
|
+
* Compute SHA256 hash of a buffer.
|
|
37
|
+
*
|
|
38
|
+
* @category Hash
|
|
39
|
+
*/
|
|
40
|
+
export declare const hashBuffer: (buffer: Buffer | Uint8Array) => Effect.Effect<ContentHash>;
|
|
41
|
+
/**
|
|
42
|
+
* Check if two hashes are equal.
|
|
43
|
+
*
|
|
44
|
+
* @category Hash
|
|
45
|
+
*/
|
|
46
|
+
export declare const hashEquals: (a: ContentHash, b: ContentHash) => boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Synchronous version of hashContent for simple use cases.
|
|
49
|
+
*
|
|
50
|
+
* @category Hash
|
|
51
|
+
*/
|
|
52
|
+
export declare const hashContentSync: (content: string) => ContentHash;
|
|
53
|
+
//# sourceMappingURL=Hash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Hash.d.ts","sourceRoot":"","sources":["../src/Hash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAExC;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,WAAW,GAAI,SAAS,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,WAAW,CAInE,CAAA;AAEJ;;;;GAIG;AACH,eAAO,MAAM,UAAU,GAAI,QAAQ,MAAM,GAAG,UAAU,KAAG,MAAM,CAAC,MAAM,CAAC,WAAW,CAI9E,CAAA;AAEJ;;;;GAIG;AACH,eAAO,MAAM,UAAU,GAAI,GAAG,WAAW,EAAE,GAAG,WAAW,KAAG,OAAkB,CAAA;AAE9E;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,SAAS,MAAM,KAAG,WAGjD,CAAA"}
|
package/dist/Hash.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SHA256 content hashing via Node.js crypto, returning branded {@link ContentHash} values.
|
|
3
|
+
*
|
|
4
|
+
* **Mental model**
|
|
5
|
+
*
|
|
6
|
+
* - **Effect-wrapped crypto**: {@link hashContent} and {@link hashBuffer} return
|
|
7
|
+
* `Effect<ContentHash>` so hashing composes into pipelines without try/catch.
|
|
8
|
+
* - **Sync escape hatch**: {@link hashContentSync} for contexts where Effect isn't needed.
|
|
9
|
+
*
|
|
10
|
+
* **Common tasks**
|
|
11
|
+
*
|
|
12
|
+
* - Hash a string: {@link hashContent}
|
|
13
|
+
* - Hash a buffer: {@link hashBuffer}
|
|
14
|
+
* - Compare hashes: {@link hashEquals}
|
|
15
|
+
*
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
import * as Effect from "effect/Effect";
|
|
19
|
+
import * as crypto from "node:crypto";
|
|
20
|
+
import { ContentHash } from "./Brand.js";
|
|
21
|
+
/**
|
|
22
|
+
* Compute SHA256 hash of a string.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* import { hashContent } from "@knpkv/atlassian-common"
|
|
27
|
+
* import * as Effect from "effect/Effect"
|
|
28
|
+
*
|
|
29
|
+
* const hash = Effect.runSync(hashContent("hello world"))
|
|
30
|
+
* // => "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @category Hash
|
|
34
|
+
*/
|
|
35
|
+
export const hashContent = (content) => Effect.sync(() => {
|
|
36
|
+
const hash = crypto.createHash("sha256").update(content, "utf8").digest("hex");
|
|
37
|
+
return ContentHash(hash);
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* Compute SHA256 hash of a buffer.
|
|
41
|
+
*
|
|
42
|
+
* @category Hash
|
|
43
|
+
*/
|
|
44
|
+
export const hashBuffer = (buffer) => Effect.sync(() => {
|
|
45
|
+
const hash = crypto.createHash("sha256").update(buffer).digest("hex");
|
|
46
|
+
return ContentHash(hash);
|
|
47
|
+
});
|
|
48
|
+
/**
|
|
49
|
+
* Check if two hashes are equal.
|
|
50
|
+
*
|
|
51
|
+
* @category Hash
|
|
52
|
+
*/
|
|
53
|
+
export const hashEquals = (a, b) => a === b;
|
|
54
|
+
/**
|
|
55
|
+
* Synchronous version of hashContent for simple use cases.
|
|
56
|
+
*
|
|
57
|
+
* @category Hash
|
|
58
|
+
*/
|
|
59
|
+
export const hashContentSync = (content) => {
|
|
60
|
+
const hash = crypto.createHash("sha256").update(content, "utf8").digest("hex");
|
|
61
|
+
return ContentHash(hash);
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=Hash.js.map
|
package/dist/Hash.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Hash.js","sourceRoot":"","sources":["../src/Hash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAExC;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,OAAe,EAA8B,EAAE,CACzE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE;IACf,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC9E,OAAO,WAAW,CAAC,IAAI,CAAC,CAAA;AAC1B,CAAC,CAAC,CAAA;AAEJ;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,MAA2B,EAA8B,EAAE,CACpF,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE;IACf,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACrE,OAAO,WAAW,CAAC,IAAI,CAAC,CAAA;AAC1B,CAAC,CAAC,CAAA;AAEJ;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAc,EAAE,CAAc,EAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAA;AAE9E;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,OAAe,EAAe,EAAE;IAC9D,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC9E,OAAO,WAAW,CAAC,IAAI,CAAC,CAAA;AAC1B,CAAC,CAAA"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
declare const SerializeError_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 & {
|
|
2
|
+
readonly _tag: "SerializeError";
|
|
3
|
+
} & Readonly<A>;
|
|
4
|
+
/**
|
|
5
|
+
* Error thrown when serializing AST fails.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { Effect } from "effect"
|
|
10
|
+
* import { SerializeError } from "@knpkv/atlassian-common"
|
|
11
|
+
*
|
|
12
|
+
* Effect.gen(function* () {
|
|
13
|
+
* // ... serialization operation
|
|
14
|
+
* }).pipe(
|
|
15
|
+
* Effect.catchTag("SerializeError", (error) =>
|
|
16
|
+
* Effect.sync(() => console.error(`Serialize error: ${error.message}`))
|
|
17
|
+
* )
|
|
18
|
+
* )
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @category Errors
|
|
22
|
+
*/
|
|
23
|
+
export declare class SerializeError extends SerializeError_base<{
|
|
24
|
+
readonly target: "confluence" | "markdown" | "adf";
|
|
25
|
+
readonly nodeType: string;
|
|
26
|
+
readonly message: string;
|
|
27
|
+
}> {
|
|
28
|
+
}
|
|
29
|
+
declare const ParseError_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 & {
|
|
30
|
+
readonly _tag: "ParseError";
|
|
31
|
+
} & Readonly<A>;
|
|
32
|
+
/**
|
|
33
|
+
* Error thrown when parsing content fails.
|
|
34
|
+
*
|
|
35
|
+
* @category Errors
|
|
36
|
+
*/
|
|
37
|
+
export declare class ParseError extends ParseError_base<{
|
|
38
|
+
readonly source: "confluence" | "markdown" | "adf";
|
|
39
|
+
readonly message: string;
|
|
40
|
+
readonly position?: {
|
|
41
|
+
readonly line: number;
|
|
42
|
+
readonly column: number;
|
|
43
|
+
};
|
|
44
|
+
readonly rawContent?: string;
|
|
45
|
+
}> {
|
|
46
|
+
}
|
|
47
|
+
export {};
|
|
48
|
+
//# sourceMappingURL=SerializeError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SerializeError.d.ts","sourceRoot":"","sources":["../src/SerializeError.ts"],"names":[],"mappings":";;;AAcA;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,cAAe,SAAQ,oBAAmC;IACrE,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,UAAU,GAAG,KAAK,CAAA;IAClD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB,CAAC;CAAG;;;;AAEL;;;;GAIG;AACH,qBAAa,UAAW,SAAQ,gBAA+B;IAC7D,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,UAAU,GAAG,KAAK,CAAA;IAClD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACtE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAC7B,CAAC;CAAG"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tagged error types for AST serialization and parsing failures.
|
|
3
|
+
*
|
|
4
|
+
* **Mental model**
|
|
5
|
+
*
|
|
6
|
+
* - **Discriminated by `_tag`**: {@link SerializeError} and {@link ParseError} extend
|
|
7
|
+
* `Data.TaggedError`, enabling `Effect.catchTag` for selective recovery.
|
|
8
|
+
* - **Direction-aware**: Both carry a `target`/`source` field (`"confluence" | "markdown" | "adf"`)
|
|
9
|
+
* so handlers know which serialization pipeline failed.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import * as Data from "effect/Data";
|
|
14
|
+
/**
|
|
15
|
+
* Error thrown when serializing AST fails.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { Effect } from "effect"
|
|
20
|
+
* import { SerializeError } from "@knpkv/atlassian-common"
|
|
21
|
+
*
|
|
22
|
+
* Effect.gen(function* () {
|
|
23
|
+
* // ... serialization operation
|
|
24
|
+
* }).pipe(
|
|
25
|
+
* Effect.catchTag("SerializeError", (error) =>
|
|
26
|
+
* Effect.sync(() => console.error(`Serialize error: ${error.message}`))
|
|
27
|
+
* )
|
|
28
|
+
* )
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @category Errors
|
|
32
|
+
*/
|
|
33
|
+
export class SerializeError extends Data.TaggedError("SerializeError") {
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Error thrown when parsing content fails.
|
|
37
|
+
*
|
|
38
|
+
* @category Errors
|
|
39
|
+
*/
|
|
40
|
+
export class ParseError extends Data.TaggedError("ParseError") {
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=SerializeError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SerializeError.js","sourceRoot":"","sources":["../src/SerializeError.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,IAAI,MAAM,aAAa,CAAA;AAEnC;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,OAAO,cAAe,SAAQ,IAAI,CAAC,WAAW,CAAC,gBAAgB,CAInE;CAAG;AAEL;;;;GAIG;AACH,MAAM,OAAO,UAAW,SAAQ,IAAI,CAAC,WAAW,CAAC,YAAY,CAK3D;CAAG"}
|