@knpkv/confluence-to-markdown 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 +12 -0
- package/README.md +62 -0
- package/dist/Brand.d.ts +77 -0
- package/dist/Brand.d.ts.map +1 -0
- package/dist/Brand.js +44 -0
- package/dist/Brand.js.map +1 -0
- package/dist/ConfluenceClient.d.ts +140 -0
- package/dist/ConfluenceClient.d.ts.map +1 -0
- package/dist/ConfluenceClient.js +195 -0
- package/dist/ConfluenceClient.js.map +1 -0
- package/dist/ConfluenceConfig.d.ts +83 -0
- package/dist/ConfluenceConfig.d.ts.map +1 -0
- package/dist/ConfluenceConfig.js +122 -0
- package/dist/ConfluenceConfig.js.map +1 -0
- package/dist/ConfluenceError.d.ts +178 -0
- package/dist/ConfluenceError.d.ts.map +1 -0
- package/dist/ConfluenceError.js +131 -0
- package/dist/ConfluenceError.js.map +1 -0
- package/dist/LocalFileSystem.d.ts +85 -0
- package/dist/LocalFileSystem.d.ts.map +1 -0
- package/dist/LocalFileSystem.js +101 -0
- package/dist/LocalFileSystem.js.map +1 -0
- package/dist/MarkdownConverter.d.ts +50 -0
- package/dist/MarkdownConverter.d.ts.map +1 -0
- package/dist/MarkdownConverter.js +151 -0
- package/dist/MarkdownConverter.js.map +1 -0
- package/dist/Schemas.d.ts +225 -0
- package/dist/Schemas.d.ts.map +1 -0
- package/dist/Schemas.js +164 -0
- package/dist/Schemas.js.map +1 -0
- package/dist/SyncEngine.d.ts +132 -0
- package/dist/SyncEngine.d.ts.map +1 -0
- package/dist/SyncEngine.js +267 -0
- package/dist/SyncEngine.js.map +1 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +163 -0
- package/dist/bin.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/frontmatter.d.ts +38 -0
- package/dist/internal/frontmatter.d.ts.map +1 -0
- package/dist/internal/frontmatter.js +69 -0
- package/dist/internal/frontmatter.js.map +1 -0
- package/dist/internal/hashUtils.d.ts +11 -0
- package/dist/internal/hashUtils.d.ts.map +1 -0
- package/dist/internal/hashUtils.js +17 -0
- package/dist/internal/hashUtils.js.map +1 -0
- package/dist/internal/pathUtils.d.ts +41 -0
- package/dist/internal/pathUtils.d.ts.map +1 -0
- package/dist/internal/pathUtils.js +69 -0
- package/dist/internal/pathUtils.js.map +1 -0
- package/package.json +113 -0
- package/src/Brand.ts +104 -0
- package/src/ConfluenceClient.ts +387 -0
- package/src/ConfluenceConfig.ts +184 -0
- package/src/ConfluenceError.ts +193 -0
- package/src/LocalFileSystem.ts +225 -0
- package/src/MarkdownConverter.ts +187 -0
- package/src/Schemas.ts +235 -0
- package/src/SyncEngine.ts +429 -0
- package/src/bin.ts +269 -0
- package/src/index.ts +35 -0
- package/src/internal/frontmatter.ts +98 -0
- package/src/internal/hashUtils.ts +19 -0
- package/src/internal/pathUtils.ts +77 -0
- package/test/Brand.test.ts +72 -0
- package/test/MarkdownConverter.test.ts +108 -0
- package/test/Schemas.test.ts +99 -0
- package/tsconfig.json +32 -0
- package/vitest.config.integration.ts +12 -0
- package/vitest.config.ts +13 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# @knpkv/confluence-to-markdown
|
|
2
|
+
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#14](https://github.com/knpkv/npm/pull/14) [`ddb73a3`](https://github.com/knpkv/npm/commit/ddb73a3b2633ec2e531ba2ff3f3a3b55fbadef3a) Thanks @konopkov! - Initial release of confluence-to-markdown package
|
|
8
|
+
- CLI with init/pull/push/sync/status commands
|
|
9
|
+
- Effect-TS based Confluence REST API v2 client
|
|
10
|
+
- Bidirectional markdown sync with frontmatter
|
|
11
|
+
- HTML to GFM conversion via rehype/remark
|
|
12
|
+
- Interactive prompts for missing CLI args
|
package/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# @knpkv/confluence-to-markdown
|
|
2
|
+
|
|
3
|
+
> **Warning**
|
|
4
|
+
> This package is experimental and in early development. Code is primarily AI-generated and not yet publicly published. For preview, use snapshot releases.
|
|
5
|
+
|
|
6
|
+
Sync Confluence Cloud pages to local GitHub Flavored Markdown files.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @knpkv/confluence-to-markdown effect
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## CLI Usage
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Initialize configuration
|
|
18
|
+
confluence init --root-page-id 123456 --base-url https://yoursite.atlassian.net
|
|
19
|
+
|
|
20
|
+
# Pull pages from Confluence
|
|
21
|
+
confluence pull
|
|
22
|
+
|
|
23
|
+
# Push local changes to Confluence
|
|
24
|
+
confluence push
|
|
25
|
+
|
|
26
|
+
# Bidirectional sync
|
|
27
|
+
confluence sync
|
|
28
|
+
|
|
29
|
+
# Check sync status
|
|
30
|
+
confluence status
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Configuration
|
|
34
|
+
|
|
35
|
+
Create `.confluence.json` in your project root:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"rootPageId": "123456",
|
|
40
|
+
"baseUrl": "https://yoursite.atlassian.net",
|
|
41
|
+
"spaceKey": "DEV",
|
|
42
|
+
"docsPath": ".docs/confluence"
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Environment Variables
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
export CONFLUENCE_API_KEY=your-api-token
|
|
50
|
+
export CONFLUENCE_EMAIL=your-email@example.com
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Known Limitations
|
|
54
|
+
|
|
55
|
+
- **Page creation**: Creating new pages from local markdown is not yet implemented
|
|
56
|
+
- **Conflict detection**: Bidirectional sync does not detect conflicts (last write wins)
|
|
57
|
+
- **Attachments**: Image and file attachments are not synced
|
|
58
|
+
- **Comments**: Page comments are not preserved
|
|
59
|
+
|
|
60
|
+
## License
|
|
61
|
+
|
|
62
|
+
MIT
|
package/dist/Brand.d.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Branded types for type-safe Confluence identifiers.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import * as Brand from "effect/Brand";
|
|
7
|
+
import * as Schema from "effect/Schema";
|
|
8
|
+
/**
|
|
9
|
+
* Branded type for Confluence page IDs.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { PageId } from "@knpkv/confluence-to-markdown/Brand"
|
|
14
|
+
*
|
|
15
|
+
* const id = PageId("12345") // Valid
|
|
16
|
+
* const invalid = PageId("") // Throws BrandErrors
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @category Brand
|
|
20
|
+
*/
|
|
21
|
+
export type PageId = string & Brand.Brand<"PageId">;
|
|
22
|
+
/**
|
|
23
|
+
* Refined brand constructor for PageId.
|
|
24
|
+
*
|
|
25
|
+
* @category Brand
|
|
26
|
+
*/
|
|
27
|
+
export declare const PageId: Brand.Brand.Constructor<PageId>;
|
|
28
|
+
/**
|
|
29
|
+
* Schema for PageId validation and parsing.
|
|
30
|
+
*
|
|
31
|
+
* @category Schema
|
|
32
|
+
*/
|
|
33
|
+
export declare const PageIdSchema: Schema.brand<Schema.filter<typeof Schema.String>, "PageId">;
|
|
34
|
+
/**
|
|
35
|
+
* Branded type for Confluence space keys.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* import { SpaceKey } from "@knpkv/confluence-to-markdown/Brand"
|
|
40
|
+
*
|
|
41
|
+
* const key = SpaceKey("DOCS") // Valid
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @category Brand
|
|
45
|
+
*/
|
|
46
|
+
export type SpaceKey = string & Brand.Brand<"SpaceKey">;
|
|
47
|
+
/**
|
|
48
|
+
* Refined brand constructor for SpaceKey.
|
|
49
|
+
*
|
|
50
|
+
* @category Brand
|
|
51
|
+
*/
|
|
52
|
+
export declare const SpaceKey: Brand.Brand.Constructor<SpaceKey>;
|
|
53
|
+
/**
|
|
54
|
+
* Schema for SpaceKey validation.
|
|
55
|
+
*
|
|
56
|
+
* @category Schema
|
|
57
|
+
*/
|
|
58
|
+
export declare const SpaceKeySchema: Schema.brand<Schema.filter<Schema.filter<typeof Schema.String>>, "SpaceKey">;
|
|
59
|
+
/**
|
|
60
|
+
* Branded type for content hash (SHA256).
|
|
61
|
+
*
|
|
62
|
+
* @category Brand
|
|
63
|
+
*/
|
|
64
|
+
export type ContentHash = string & Brand.Brand<"ContentHash">;
|
|
65
|
+
/**
|
|
66
|
+
* Refined brand constructor for ContentHash.
|
|
67
|
+
*
|
|
68
|
+
* @category Brand
|
|
69
|
+
*/
|
|
70
|
+
export declare const ContentHash: Brand.Brand.Constructor<ContentHash>;
|
|
71
|
+
/**
|
|
72
|
+
* Schema for ContentHash validation.
|
|
73
|
+
*
|
|
74
|
+
* @category Schema
|
|
75
|
+
*/
|
|
76
|
+
export declare const ContentHashSchema: Schema.brand<Schema.filter<typeof Schema.String>, "ContentHash">;
|
|
77
|
+
//# sourceMappingURL=Brand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Brand.d.ts","sourceRoot":"","sources":["../src/Brand.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;AAEnD;;;;GAIG;AACH,eAAO,MAAM,MAAM,iCAGlB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,YAAY,6DAGxB,CAAA;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;AAEvD;;;;GAIG;AACH,eAAO,MAAM,QAAQ,mCAGpB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,cAAc,8EAI1B,CAAA;AAED;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,CAAA;AAE7D;;;;GAIG;AACH,eAAO,MAAM,WAAW,sCAGvB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,kEAG7B,CAAA"}
|
package/dist/Brand.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Branded types for type-safe Confluence identifiers.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import * as Brand from "effect/Brand";
|
|
7
|
+
import * as Schema from "effect/Schema";
|
|
8
|
+
/**
|
|
9
|
+
* Refined brand constructor for PageId.
|
|
10
|
+
*
|
|
11
|
+
* @category Brand
|
|
12
|
+
*/
|
|
13
|
+
export const PageId = Brand.refined((s) => typeof s === "string" && s.length > 0, (s) => Brand.error(`Invalid page ID: "${s}" (must be non-empty string)`));
|
|
14
|
+
/**
|
|
15
|
+
* Schema for PageId validation and parsing.
|
|
16
|
+
*
|
|
17
|
+
* @category Schema
|
|
18
|
+
*/
|
|
19
|
+
export const PageIdSchema = Schema.String.pipe(Schema.nonEmptyString(), Schema.brand("PageId"));
|
|
20
|
+
/**
|
|
21
|
+
* Refined brand constructor for SpaceKey.
|
|
22
|
+
*
|
|
23
|
+
* @category Brand
|
|
24
|
+
*/
|
|
25
|
+
export const SpaceKey = Brand.refined((s) => typeof s === "string" && s.length > 0 && /^[A-Z0-9]+$/.test(s), (s) => Brand.error(`Invalid space key: "${s}" (must be uppercase alphanumeric)`));
|
|
26
|
+
/**
|
|
27
|
+
* Schema for SpaceKey validation.
|
|
28
|
+
*
|
|
29
|
+
* @category Schema
|
|
30
|
+
*/
|
|
31
|
+
export const SpaceKeySchema = Schema.String.pipe(Schema.nonEmptyString(), Schema.pattern(/^[A-Z0-9]+$/), Schema.brand("SpaceKey"));
|
|
32
|
+
/**
|
|
33
|
+
* Refined brand constructor for ContentHash.
|
|
34
|
+
*
|
|
35
|
+
* @category Brand
|
|
36
|
+
*/
|
|
37
|
+
export const ContentHash = Brand.refined((s) => typeof s === "string" && /^[a-f0-9]{64}$/.test(s), (s) => Brand.error(`Invalid content hash: "${s}" (must be 64-char hex string)`));
|
|
38
|
+
/**
|
|
39
|
+
* Schema for ContentHash validation.
|
|
40
|
+
*
|
|
41
|
+
* @category Schema
|
|
42
|
+
*/
|
|
43
|
+
export const ContentHashSchema = Schema.String.pipe(Schema.pattern(/^[a-f0-9]{64}$/), Schema.brand("ContentHash"));
|
|
44
|
+
//# sourceMappingURL=Brand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Brand.js","sourceRoot":"","sources":["../src/Brand.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAiBvC;;;;GAIG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CACjC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EACzD,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,qBAAqB,CAAC,8BAA8B,CAAC,CACzE,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAC5C,MAAM,CAAC,cAAc,EAAE,EACvB,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CACvB,CAAA;AAgBD;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CACnC,CAAC,CAAC,EAAiB,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EACpF,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,uBAAuB,CAAC,oCAAoC,CAAC,CACjF,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAC9C,MAAM,CAAC,cAAc,EAAE,EACvB,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,EAC7B,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CACzB,CAAA;AASD;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CACtC,CAAC,CAAC,EAAoB,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAC1E,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,0BAA0B,CAAC,gCAAgC,CAAC,CAChF,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CACjD,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAChC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAC5B,CAAA"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Confluence REST API v2 client service.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import * as HttpClient from "@effect/platform/HttpClient";
|
|
7
|
+
import * as Context from "effect/Context";
|
|
8
|
+
import * as Effect from "effect/Effect";
|
|
9
|
+
import * as Layer from "effect/Layer";
|
|
10
|
+
import type { PageId } from "./Brand.js";
|
|
11
|
+
import { ApiError, RateLimitError } from "./ConfluenceError.js";
|
|
12
|
+
import type { PageChildrenResponse, PageListItem, PageResponse } from "./Schemas.js";
|
|
13
|
+
/**
|
|
14
|
+
* Request to create a new page.
|
|
15
|
+
*
|
|
16
|
+
* @category Types
|
|
17
|
+
*/
|
|
18
|
+
export interface CreatePageRequest {
|
|
19
|
+
readonly spaceId: string;
|
|
20
|
+
readonly title: string;
|
|
21
|
+
readonly parentId?: string;
|
|
22
|
+
readonly body: {
|
|
23
|
+
readonly representation: "storage";
|
|
24
|
+
readonly value: string;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Request to update an existing page.
|
|
29
|
+
*
|
|
30
|
+
* @category Types
|
|
31
|
+
*/
|
|
32
|
+
export interface UpdatePageRequest {
|
|
33
|
+
readonly id: string;
|
|
34
|
+
readonly title: string;
|
|
35
|
+
readonly status?: "current" | "draft";
|
|
36
|
+
readonly version: {
|
|
37
|
+
readonly number: number;
|
|
38
|
+
readonly message?: string;
|
|
39
|
+
};
|
|
40
|
+
readonly body: {
|
|
41
|
+
readonly representation: "storage";
|
|
42
|
+
readonly value: string;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
declare const ConfluenceClient_base: Context.TagClass<ConfluenceClient, "@knpkv/confluence-to-markdown/ConfluenceClient", {
|
|
46
|
+
/**
|
|
47
|
+
* Get a page by ID.
|
|
48
|
+
*/
|
|
49
|
+
readonly getPage: (id: PageId) => Effect.Effect<PageResponse, ApiError | RateLimitError>;
|
|
50
|
+
/**
|
|
51
|
+
* Get children of a page.
|
|
52
|
+
*/
|
|
53
|
+
readonly getChildren: (id: PageId) => Effect.Effect<PageChildrenResponse, ApiError | RateLimitError>;
|
|
54
|
+
/**
|
|
55
|
+
* Get all children recursively (handles pagination).
|
|
56
|
+
*/
|
|
57
|
+
readonly getAllChildren: (id: PageId) => Effect.Effect<ReadonlyArray<PageListItem>, ApiError | RateLimitError>;
|
|
58
|
+
/**
|
|
59
|
+
* Create a new page.
|
|
60
|
+
*/
|
|
61
|
+
readonly createPage: (request: CreatePageRequest) => Effect.Effect<PageResponse, ApiError | RateLimitError>;
|
|
62
|
+
/**
|
|
63
|
+
* Update an existing page.
|
|
64
|
+
*/
|
|
65
|
+
readonly updatePage: (request: UpdatePageRequest) => Effect.Effect<PageResponse, ApiError | RateLimitError>;
|
|
66
|
+
/**
|
|
67
|
+
* Delete a page.
|
|
68
|
+
*/
|
|
69
|
+
readonly deletePage: (id: PageId) => Effect.Effect<void, ApiError | RateLimitError>;
|
|
70
|
+
}>;
|
|
71
|
+
/**
|
|
72
|
+
* Confluence REST API v2 client service.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* import { ConfluenceClient } from "@knpkv/confluence-to-markdown/ConfluenceClient"
|
|
77
|
+
* import { Effect } from "effect"
|
|
78
|
+
*
|
|
79
|
+
* const program = Effect.gen(function* () {
|
|
80
|
+
* const client = yield* ConfluenceClient
|
|
81
|
+
* const page = yield* client.getPage("12345")
|
|
82
|
+
* console.log(page.title)
|
|
83
|
+
* })
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* @category Client
|
|
87
|
+
*/
|
|
88
|
+
export declare class ConfluenceClient extends ConfluenceClient_base {
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Configuration for the Confluence client.
|
|
92
|
+
*
|
|
93
|
+
* @category Config
|
|
94
|
+
*/
|
|
95
|
+
export interface ConfluenceClientConfig {
|
|
96
|
+
readonly baseUrl: string;
|
|
97
|
+
readonly auth: {
|
|
98
|
+
readonly type: "token";
|
|
99
|
+
readonly email: string;
|
|
100
|
+
readonly token: string;
|
|
101
|
+
} | {
|
|
102
|
+
readonly type: "oauth2";
|
|
103
|
+
readonly accessToken: string;
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Layer that provides ConfluenceClient with direct configuration.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```typescript
|
|
111
|
+
* import { ConfluenceClient } from "@knpkv/confluence-to-markdown/ConfluenceClient"
|
|
112
|
+
* import { NodeHttpClient } from "@effect/platform-node"
|
|
113
|
+
* import { Effect } from "effect"
|
|
114
|
+
*
|
|
115
|
+
* const program = Effect.gen(function* () {
|
|
116
|
+
* const client = yield* ConfluenceClient
|
|
117
|
+
* const page = yield* client.getPage("12345")
|
|
118
|
+
* console.log(page.title)
|
|
119
|
+
* })
|
|
120
|
+
*
|
|
121
|
+
* Effect.runPromise(
|
|
122
|
+
* program.pipe(
|
|
123
|
+
* Effect.provide(ConfluenceClient.layer({
|
|
124
|
+
* baseUrl: "https://yoursite.atlassian.net",
|
|
125
|
+
* auth: {
|
|
126
|
+
* type: "token",
|
|
127
|
+
* email: "you@example.com",
|
|
128
|
+
* token: process.env.CONFLUENCE_API_KEY
|
|
129
|
+
* }
|
|
130
|
+
* })),
|
|
131
|
+
* Effect.provide(NodeHttpClient.layer)
|
|
132
|
+
* )
|
|
133
|
+
* )
|
|
134
|
+
* ```
|
|
135
|
+
*
|
|
136
|
+
* @category Layers
|
|
137
|
+
*/
|
|
138
|
+
export declare const layer: (config: ConfluenceClientConfig) => Layer.Layer<ConfluenceClient, never, HttpClient.HttpClient>;
|
|
139
|
+
export {};
|
|
140
|
+
//# sourceMappingURL=ConfluenceClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfluenceClient.d.ts","sourceRoot":"","sources":["../src/ConfluenceClient.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,UAAU,MAAM,6BAA6B,CAAA;AAEzD,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AACzC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAGrC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAC/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAGpF;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,IAAI,EAAE;QACb,QAAQ,CAAC,cAAc,EAAE,SAAS,CAAA;QAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KACvB,CAAA;CACF;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,OAAO,CAAA;IACrC,QAAQ,CAAC,OAAO,EAAE;QAChB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;QACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAC1B,CAAA;IACD,QAAQ,CAAC,IAAI,EAAE;QACb,QAAQ,CAAC,cAAc,EAAE,SAAS,CAAA;QAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KACvB,CAAA;CACF;;IAwBG;;OAEG;sBACe,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,QAAQ,GAAG,cAAc,CAAC;IAExF;;OAEG;0BACmB,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,oBAAoB,EAAE,QAAQ,GAAG,cAAc,CAAC;IAEpG;;OAEG;6BACsB,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,EAAE,QAAQ,GAAG,cAAc,CAAC;IAE9G;;OAEG;yBACkB,CAAC,OAAO,EAAE,iBAAiB,KAAK,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,QAAQ,GAAG,cAAc,CAAC;IAE3G;;OAEG;yBACkB,CAAC,OAAO,EAAE,iBAAiB,KAAK,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,QAAQ,GAAG,cAAc,CAAC;IAE3G;;OAEG;yBACkB,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,GAAG,cAAc,CAAC;;AAlDvF;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,gBAAiB,SAAQ,qBAmCnC;CAAG;AAEN;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,IAAI,EAAE;QACb,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;QACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;QACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KACvB,GAAG;QACF,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;QACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;KAC7B,CAAA;CACF;AAoOD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,KAAK,GAChB,QAAQ,sBAAsB,KAC7B,KAAK,CAAC,KAAK,CAAC,gBAAgB,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CAAiD,CAAA"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Confluence REST API v2 client service.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import * as HttpClient from "@effect/platform/HttpClient";
|
|
7
|
+
import * as HttpClientRequest from "@effect/platform/HttpClientRequest";
|
|
8
|
+
import * as Context from "effect/Context";
|
|
9
|
+
import * as Effect from "effect/Effect";
|
|
10
|
+
import * as Layer from "effect/Layer";
|
|
11
|
+
import * as Schedule from "effect/Schedule";
|
|
12
|
+
import * as Schema from "effect/Schema";
|
|
13
|
+
import { ApiError, RateLimitError } from "./ConfluenceError.js";
|
|
14
|
+
import { PageChildrenResponseSchema, PageResponseSchema } from "./Schemas.js";
|
|
15
|
+
/**
|
|
16
|
+
* Confluence REST API v2 client service.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import { ConfluenceClient } from "@knpkv/confluence-to-markdown/ConfluenceClient"
|
|
21
|
+
* import { Effect } from "effect"
|
|
22
|
+
*
|
|
23
|
+
* const program = Effect.gen(function* () {
|
|
24
|
+
* const client = yield* ConfluenceClient
|
|
25
|
+
* const page = yield* client.getPage("12345")
|
|
26
|
+
* console.log(page.title)
|
|
27
|
+
* })
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @category Client
|
|
31
|
+
*/
|
|
32
|
+
export class ConfluenceClient extends Context.Tag("@knpkv/confluence-to-markdown/ConfluenceClient")() {
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Rate limit retry schedule with exponential backoff.
|
|
36
|
+
*/
|
|
37
|
+
const rateLimitSchedule = Schedule.exponential("1 second").pipe(Schedule.union(Schedule.spaced("30 seconds")), Schedule.whileInput((error) => error._tag === "RateLimitError"), Schedule.intersect(Schedule.recurs(3)));
|
|
38
|
+
/**
|
|
39
|
+
* Create the Confluence client service.
|
|
40
|
+
*/
|
|
41
|
+
const make = (config) => Effect.gen(function* () {
|
|
42
|
+
const httpClient = yield* HttpClient.HttpClient;
|
|
43
|
+
const authHeader = config.auth.type === "token"
|
|
44
|
+
? `Basic ${Buffer.from(`${config.auth.email}:${config.auth.token}`).toString("base64")}`
|
|
45
|
+
: `Bearer ${config.auth.accessToken}`;
|
|
46
|
+
const baseRequest = HttpClientRequest.get(`${config.baseUrl}/wiki/api/v2`).pipe(HttpClientRequest.setHeader("Authorization", authHeader), HttpClientRequest.setHeader("Accept", "application/json"), HttpClientRequest.setHeader("Content-Type", "application/json"));
|
|
47
|
+
const request = (method, path, body) => Effect.gen(function* () {
|
|
48
|
+
let req = baseRequest.pipe(HttpClientRequest.setMethod(method), HttpClientRequest.setUrl(`${config.baseUrl}/wiki/api/v2${path}`));
|
|
49
|
+
if (body !== undefined) {
|
|
50
|
+
req = HttpClientRequest.bodyJson(req, body).pipe(Effect.catchAll(() => Effect.succeed(req)), Effect.runSync);
|
|
51
|
+
}
|
|
52
|
+
const response = yield* httpClient.execute(req).pipe(Effect.mapError((error) => new ApiError({
|
|
53
|
+
status: 0,
|
|
54
|
+
message: `Request failed: ${error.message}`,
|
|
55
|
+
endpoint: path
|
|
56
|
+
})));
|
|
57
|
+
if (response.status === 429) {
|
|
58
|
+
const retryAfterHeader = response.headers["retry-after"];
|
|
59
|
+
const retryAfter = retryAfterHeader ? parseInt(retryAfterHeader, 10) : undefined;
|
|
60
|
+
return yield* Effect.fail(retryAfter !== undefined
|
|
61
|
+
? new RateLimitError({ retryAfter })
|
|
62
|
+
: new RateLimitError({}));
|
|
63
|
+
}
|
|
64
|
+
if (response.status >= 400) {
|
|
65
|
+
const text = yield* response.text.pipe(Effect.catchAll(() => Effect.succeed("")));
|
|
66
|
+
return yield* Effect.fail(new ApiError({
|
|
67
|
+
status: response.status,
|
|
68
|
+
message: text || `HTTP ${response.status}`,
|
|
69
|
+
endpoint: path
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
if (method === "DELETE" && response.status === 204) {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
const json = yield* response.json.pipe(Effect.mapError((error) => new ApiError({
|
|
76
|
+
status: response.status,
|
|
77
|
+
message: `Failed to parse response: ${error}`,
|
|
78
|
+
endpoint: path
|
|
79
|
+
})));
|
|
80
|
+
return json;
|
|
81
|
+
}).pipe(Effect.retry(rateLimitSchedule));
|
|
82
|
+
const getPage = (id) => Effect.gen(function* () {
|
|
83
|
+
const raw = yield* request("GET", `/pages/${id}?body-format=storage`);
|
|
84
|
+
return yield* Schema.decodeUnknown(PageResponseSchema)(raw).pipe(Effect.mapError((error) => new ApiError({
|
|
85
|
+
status: 0,
|
|
86
|
+
message: `Invalid response schema: ${error.message}`,
|
|
87
|
+
endpoint: `/pages/${id}`,
|
|
88
|
+
pageId: id
|
|
89
|
+
})));
|
|
90
|
+
});
|
|
91
|
+
const getChildren = (id) => Effect.gen(function* () {
|
|
92
|
+
const raw = yield* request("GET", `/pages/${id}/children?body-format=storage`);
|
|
93
|
+
return yield* Schema.decodeUnknown(PageChildrenResponseSchema)(raw).pipe(Effect.mapError((error) => new ApiError({
|
|
94
|
+
status: 0,
|
|
95
|
+
message: `Invalid response schema: ${error.message}`,
|
|
96
|
+
endpoint: `/pages/${id}/children`,
|
|
97
|
+
pageId: id
|
|
98
|
+
})));
|
|
99
|
+
});
|
|
100
|
+
const getAllChildren = (id) => Effect.gen(function* () {
|
|
101
|
+
const allChildren = [];
|
|
102
|
+
let cursor;
|
|
103
|
+
let iterations = 0;
|
|
104
|
+
const maxIterations = 100; // Prevent unbounded pagination
|
|
105
|
+
do {
|
|
106
|
+
if (iterations >= maxIterations) {
|
|
107
|
+
return yield* Effect.fail(new ApiError({
|
|
108
|
+
status: 0,
|
|
109
|
+
message: `Pagination limit exceeded: more than ${maxIterations} pages of children`,
|
|
110
|
+
endpoint: `/pages/${id}/children`,
|
|
111
|
+
pageId: id
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
const path = cursor
|
|
115
|
+
? `/pages/${id}/children?body-format=storage&cursor=${cursor}`
|
|
116
|
+
: `/pages/${id}/children?body-format=storage`;
|
|
117
|
+
const raw = yield* request("GET", path);
|
|
118
|
+
const response = yield* Schema.decodeUnknown(PageChildrenResponseSchema)(raw).pipe(Effect.mapError((error) => new ApiError({
|
|
119
|
+
status: 0,
|
|
120
|
+
message: `Invalid response schema: ${error.message}`,
|
|
121
|
+
endpoint: path,
|
|
122
|
+
pageId: id
|
|
123
|
+
})));
|
|
124
|
+
for (const child of response.results) {
|
|
125
|
+
allChildren.push(child);
|
|
126
|
+
}
|
|
127
|
+
// Extract cursor from next link if present
|
|
128
|
+
cursor = response._links?.next
|
|
129
|
+
? new URL(response._links.next, config.baseUrl).searchParams.get("cursor") ?? undefined
|
|
130
|
+
: undefined;
|
|
131
|
+
iterations++;
|
|
132
|
+
} while (cursor);
|
|
133
|
+
return allChildren;
|
|
134
|
+
});
|
|
135
|
+
const createPage = (req) => Effect.gen(function* () {
|
|
136
|
+
const raw = yield* request("POST", "/pages", req);
|
|
137
|
+
return yield* Schema.decodeUnknown(PageResponseSchema)(raw).pipe(Effect.mapError((error) => new ApiError({
|
|
138
|
+
status: 0,
|
|
139
|
+
message: `Invalid response schema: ${error.message}`,
|
|
140
|
+
endpoint: "/pages"
|
|
141
|
+
})));
|
|
142
|
+
});
|
|
143
|
+
const updatePage = (req) => Effect.gen(function* () {
|
|
144
|
+
const raw = yield* request("PUT", `/pages/${req.id}`, req);
|
|
145
|
+
return yield* Schema.decodeUnknown(PageResponseSchema)(raw).pipe(Effect.mapError((error) => new ApiError({
|
|
146
|
+
status: 0,
|
|
147
|
+
message: `Invalid response schema: ${error.message}`,
|
|
148
|
+
endpoint: `/pages/${req.id}`,
|
|
149
|
+
pageId: req.id
|
|
150
|
+
})));
|
|
151
|
+
});
|
|
152
|
+
const deletePage = (id) => request("DELETE", `/pages/${id}`);
|
|
153
|
+
return ConfluenceClient.of({
|
|
154
|
+
getPage,
|
|
155
|
+
getChildren,
|
|
156
|
+
getAllChildren,
|
|
157
|
+
createPage,
|
|
158
|
+
updatePage,
|
|
159
|
+
deletePage
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
/**
|
|
163
|
+
* Layer that provides ConfluenceClient with direct configuration.
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```typescript
|
|
167
|
+
* import { ConfluenceClient } from "@knpkv/confluence-to-markdown/ConfluenceClient"
|
|
168
|
+
* import { NodeHttpClient } from "@effect/platform-node"
|
|
169
|
+
* import { Effect } from "effect"
|
|
170
|
+
*
|
|
171
|
+
* const program = Effect.gen(function* () {
|
|
172
|
+
* const client = yield* ConfluenceClient
|
|
173
|
+
* const page = yield* client.getPage("12345")
|
|
174
|
+
* console.log(page.title)
|
|
175
|
+
* })
|
|
176
|
+
*
|
|
177
|
+
* Effect.runPromise(
|
|
178
|
+
* program.pipe(
|
|
179
|
+
* Effect.provide(ConfluenceClient.layer({
|
|
180
|
+
* baseUrl: "https://yoursite.atlassian.net",
|
|
181
|
+
* auth: {
|
|
182
|
+
* type: "token",
|
|
183
|
+
* email: "you@example.com",
|
|
184
|
+
* token: process.env.CONFLUENCE_API_KEY
|
|
185
|
+
* }
|
|
186
|
+
* })),
|
|
187
|
+
* Effect.provide(NodeHttpClient.layer)
|
|
188
|
+
* )
|
|
189
|
+
* )
|
|
190
|
+
* ```
|
|
191
|
+
*
|
|
192
|
+
* @category Layers
|
|
193
|
+
*/
|
|
194
|
+
export const layer = (config) => Layer.effect(ConfluenceClient, make(config));
|
|
195
|
+
//# sourceMappingURL=ConfluenceClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfluenceClient.js","sourceRoot":"","sources":["../src/ConfluenceClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration service for Confluence sync.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import * as FileSystem from "@effect/platform/FileSystem";
|
|
7
|
+
import * as Path from "@effect/platform/Path";
|
|
8
|
+
import * as Context from "effect/Context";
|
|
9
|
+
import * as Effect from "effect/Effect";
|
|
10
|
+
import * as Layer from "effect/Layer";
|
|
11
|
+
import type { PageId } from "./Brand.js";
|
|
12
|
+
import { ConfigNotFoundError, ConfigParseError } from "./ConfluenceError.js";
|
|
13
|
+
import type { ConfluenceConfigFile } from "./Schemas.js";
|
|
14
|
+
declare const ConfluenceConfig_base: Context.TagClass<ConfluenceConfig, "@knpkv/confluence-to-markdown/ConfluenceConfig", {
|
|
15
|
+
/** Root page ID to sync from */
|
|
16
|
+
readonly rootPageId: PageId;
|
|
17
|
+
/** Confluence Cloud base URL */
|
|
18
|
+
readonly baseUrl: string;
|
|
19
|
+
/** Optional space key */
|
|
20
|
+
readonly spaceKey?: string;
|
|
21
|
+
/** Local docs path */
|
|
22
|
+
readonly docsPath: string;
|
|
23
|
+
/** Glob patterns to exclude */
|
|
24
|
+
readonly excludePatterns: ReadonlyArray<string>;
|
|
25
|
+
}>;
|
|
26
|
+
/**
|
|
27
|
+
* Configuration service for Confluence operations.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* import { ConfluenceConfig } from "@knpkv/confluence-to-markdown/ConfluenceConfig"
|
|
32
|
+
* import { Effect } from "effect"
|
|
33
|
+
*
|
|
34
|
+
* const program = Effect.gen(function* () {
|
|
35
|
+
* const config = yield* ConfluenceConfig
|
|
36
|
+
* console.log(config.rootPageId)
|
|
37
|
+
* console.log(config.baseUrl)
|
|
38
|
+
* })
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @category Config
|
|
42
|
+
*/
|
|
43
|
+
export declare class ConfluenceConfig extends ConfluenceConfig_base {
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Layer that provides ConfluenceConfig from a config file.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* import { ConfluenceConfig } from "@knpkv/confluence-to-markdown/ConfluenceConfig"
|
|
51
|
+
* import { NodeFileSystem } from "@effect/platform-node"
|
|
52
|
+
* import { Effect } from "effect"
|
|
53
|
+
*
|
|
54
|
+
* const program = Effect.gen(function* () {
|
|
55
|
+
* const config = yield* ConfluenceConfig
|
|
56
|
+
* console.log(config.rootPageId)
|
|
57
|
+
* })
|
|
58
|
+
*
|
|
59
|
+
* Effect.runPromise(
|
|
60
|
+
* program.pipe(
|
|
61
|
+
* Effect.provide(ConfluenceConfig.layer()),
|
|
62
|
+
* Effect.provide(NodeFileSystem.layer)
|
|
63
|
+
* )
|
|
64
|
+
* )
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* @category Layers
|
|
68
|
+
*/
|
|
69
|
+
export declare const layer: (configPath?: string) => Layer.Layer<ConfluenceConfig, ConfigNotFoundError | ConfigParseError, FileSystem.FileSystem | Path.Path>;
|
|
70
|
+
/**
|
|
71
|
+
* Layer that provides ConfluenceConfig with direct values.
|
|
72
|
+
*
|
|
73
|
+
* @category Layers
|
|
74
|
+
*/
|
|
75
|
+
export declare const layerFromValues: (config: ConfluenceConfigFile) => Layer.Layer<ConfluenceConfig>;
|
|
76
|
+
/**
|
|
77
|
+
* Create a new config file.
|
|
78
|
+
*
|
|
79
|
+
* @category Utilities
|
|
80
|
+
*/
|
|
81
|
+
export declare const createConfigFile: (rootPageId: string, baseUrl: string, configPath?: string) => Effect.Effect<string, ConfigParseError, FileSystem.FileSystem | Path.Path>;
|
|
82
|
+
export {};
|
|
83
|
+
//# sourceMappingURL=ConfluenceConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfluenceConfig.d.ts","sourceRoot":"","sources":["../src/ConfluenceConfig.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,UAAU,MAAM,6BAA6B,CAAA;AACzD,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAA;AAC7C,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AACzC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAErC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC5E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;;IAyBpD,gCAAgC;yBACX,MAAM;IAC3B,gCAAgC;sBACd,MAAM;IACxB,yBAAyB;wBACL,MAAM;IAC1B,sBAAsB;uBACH,MAAM;IACzB,+BAA+B;8BACL,aAAa,CAAC,MAAM,CAAC;;AA/BnD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,gBAAiB,SAAQ,qBAgBnC;CAAG;AAqCN;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,KAAK,GAChB,aAAa,MAAM,KAClB,KAAK,CAAC,KAAK,CAAC,gBAAgB,EAAE,mBAAmB,GAAG,gBAAgB,EAAE,UAAU,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CAgBvG,CAAA;AAEH;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAC1B,QAAQ,oBAAoB,KAC3B,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAU5B,CAAA;AAEH;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAC3B,YAAY,MAAM,EAClB,SAAS,MAAM,EACf,aAAa,MAAM,KAClB,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,EAAE,UAAU,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CAyBxE,CAAA"}
|