@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.
Files changed (121) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +21 -0
  3. package/README.md +107 -0
  4. package/dist/Brand.d.ts +118 -0
  5. package/dist/Brand.d.ts.map +1 -0
  6. package/dist/Brand.js +107 -0
  7. package/dist/Brand.js.map +1 -0
  8. package/dist/Hash.d.ts +53 -0
  9. package/dist/Hash.d.ts.map +1 -0
  10. package/dist/Hash.js +63 -0
  11. package/dist/Hash.js.map +1 -0
  12. package/dist/SerializeError.d.ts +48 -0
  13. package/dist/SerializeError.d.ts.map +1 -0
  14. package/dist/SerializeError.js +42 -0
  15. package/dist/SerializeError.js.map +1 -0
  16. package/dist/ast/BlockNode.d.ts +429 -0
  17. package/dist/ast/BlockNode.d.ts.map +1 -0
  18. package/dist/ast/BlockNode.js +279 -0
  19. package/dist/ast/BlockNode.js.map +1 -0
  20. package/dist/ast/Document.d.ts +255 -0
  21. package/dist/ast/Document.d.ts.map +1 -0
  22. package/dist/ast/Document.js +80 -0
  23. package/dist/ast/Document.js.map +1 -0
  24. package/dist/ast/InlineNode.d.ts +483 -0
  25. package/dist/ast/InlineNode.d.ts.map +1 -0
  26. package/dist/ast/InlineNode.js +268 -0
  27. package/dist/ast/InlineNode.js.map +1 -0
  28. package/dist/ast/MacroNode.d.ts +214 -0
  29. package/dist/ast/MacroNode.d.ts.map +1 -0
  30. package/dist/ast/MacroNode.js +110 -0
  31. package/dist/ast/MacroNode.js.map +1 -0
  32. package/dist/ast/index.d.ts +10 -0
  33. package/dist/ast/index.d.ts.map +1 -0
  34. package/dist/ast/index.js +14 -0
  35. package/dist/ast/index.js.map +1 -0
  36. package/dist/auth/OAuthEndpoints.d.ts +95 -0
  37. package/dist/auth/OAuthEndpoints.d.ts.map +1 -0
  38. package/dist/auth/OAuthEndpoints.js +112 -0
  39. package/dist/auth/OAuthEndpoints.js.map +1 -0
  40. package/dist/auth/OAuthErrors.d.ts +76 -0
  41. package/dist/auth/OAuthErrors.d.ts.map +1 -0
  42. package/dist/auth/OAuthErrors.js +85 -0
  43. package/dist/auth/OAuthErrors.js.map +1 -0
  44. package/dist/auth/OAuthOperations.d.ts +87 -0
  45. package/dist/auth/OAuthOperations.d.ts.map +1 -0
  46. package/dist/auth/OAuthOperations.js +169 -0
  47. package/dist/auth/OAuthOperations.js.map +1 -0
  48. package/dist/auth/OAuthResponseSchemas.d.ts +65 -0
  49. package/dist/auth/OAuthResponseSchemas.d.ts.map +1 -0
  50. package/dist/auth/OAuthResponseSchemas.js +47 -0
  51. package/dist/auth/OAuthResponseSchemas.js.map +1 -0
  52. package/dist/auth/index.d.ts +11 -0
  53. package/dist/auth/index.d.ts.map +1 -0
  54. package/dist/auth/index.js +16 -0
  55. package/dist/auth/index.js.map +1 -0
  56. package/dist/auth/uuid.d.ts +14 -0
  57. package/dist/auth/uuid.d.ts.map +1 -0
  58. package/dist/auth/uuid.js +14 -0
  59. package/dist/auth/uuid.js.map +1 -0
  60. package/dist/config/ConfigPaths.d.ts +95 -0
  61. package/dist/config/ConfigPaths.d.ts.map +1 -0
  62. package/dist/config/ConfigPaths.js +102 -0
  63. package/dist/config/ConfigPaths.js.map +1 -0
  64. package/dist/config/OAuthSchemas.d.ts +144 -0
  65. package/dist/config/OAuthSchemas.d.ts.map +1 -0
  66. package/dist/config/OAuthSchemas.js +107 -0
  67. package/dist/config/OAuthSchemas.js.map +1 -0
  68. package/dist/config/TokenStorage.d.ts +96 -0
  69. package/dist/config/TokenStorage.d.ts.map +1 -0
  70. package/dist/config/TokenStorage.js +128 -0
  71. package/dist/config/TokenStorage.js.map +1 -0
  72. package/dist/config/index.d.ts +9 -0
  73. package/dist/config/index.d.ts.map +1 -0
  74. package/dist/config/index.js +12 -0
  75. package/dist/config/index.js.map +1 -0
  76. package/dist/index.d.ts +13 -0
  77. package/dist/index.d.ts.map +1 -0
  78. package/dist/index.js +20 -0
  79. package/dist/index.js.map +1 -0
  80. package/dist/parsers/index.d.ts +7 -0
  81. package/dist/parsers/index.d.ts.map +1 -0
  82. package/dist/parsers/index.js +8 -0
  83. package/dist/parsers/index.js.map +1 -0
  84. package/dist/serializers/MarkdownSerializer.d.ts +63 -0
  85. package/dist/serializers/MarkdownSerializer.d.ts.map +1 -0
  86. package/dist/serializers/MarkdownSerializer.js +367 -0
  87. package/dist/serializers/MarkdownSerializer.js.map +1 -0
  88. package/dist/serializers/index.d.ts +7 -0
  89. package/dist/serializers/index.d.ts.map +1 -0
  90. package/dist/serializers/index.js +7 -0
  91. package/dist/serializers/index.js.map +1 -0
  92. package/package.json +86 -0
  93. package/src/Brand.ts +142 -0
  94. package/src/Hash.ts +68 -0
  95. package/src/SerializeError.ts +50 -0
  96. package/src/ast/BlockNode.ts +386 -0
  97. package/src/ast/Document.ts +101 -0
  98. package/src/ast/InlineNode.ts +328 -0
  99. package/src/ast/MacroNode.ts +172 -0
  100. package/src/ast/index.ts +87 -0
  101. package/src/auth/OAuthEndpoints.ts +142 -0
  102. package/src/auth/OAuthErrors.ts +101 -0
  103. package/src/auth/OAuthOperations.ts +276 -0
  104. package/src/auth/OAuthResponseSchemas.ts +70 -0
  105. package/src/auth/index.ts +47 -0
  106. package/src/auth/uuid.ts +14 -0
  107. package/src/config/ConfigPaths.ts +179 -0
  108. package/src/config/OAuthSchemas.ts +146 -0
  109. package/src/config/TokenStorage.ts +228 -0
  110. package/src/config/index.ts +43 -0
  111. package/src/index.ts +34 -0
  112. package/src/parsers/index.ts +8 -0
  113. package/src/serializers/MarkdownSerializer.ts +498 -0
  114. package/src/serializers/index.ts +7 -0
  115. package/test/Brand.test.ts +90 -0
  116. package/test/MarkdownSerializer.test.ts +82 -0
  117. package/test/OAuthEndpoints.test.ts +109 -0
  118. package/test/OAuthOperations.test.ts +315 -0
  119. package/tsconfig.json +11 -0
  120. package/tsconfig.tsbuildinfo +1 -0
  121. package/vitest.config.ts +12 -0
@@ -0,0 +1,328 @@
1
+ /**
2
+ * Inline-level AST nodes for text content (emphasis, links, mentions, etc.).
3
+ *
4
+ * **Mental model**
5
+ *
6
+ * - **Leaf and recursive nodes**: `Text`, `InlineCode`, `LineBreak` are leaves;
7
+ * `Strong`, `Emphasis`, `Highlight` contain nested `InlineNode` children via `Schema.suspend`.
8
+ * - **Unsupported preservation**: {@link UnsupportedInline} captures raw content that can't be
9
+ * mapped, enabling non-destructive roundtrips.
10
+ *
11
+ * @module
12
+ */
13
+ import * as Schema from "effect/Schema"
14
+
15
+ /**
16
+ * Optional raw source HTML for exact roundtrip preservation.
17
+ *
18
+ * @category InlineNode
19
+ */
20
+ export const RawSource = Schema.optional(Schema.String)
21
+
22
+ /**
23
+ * Plain text content.
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * import { Text } from "@knpkv/atlassian-common/ast"
28
+ *
29
+ * const text = new Text({ value: "Hello world" })
30
+ * ```
31
+ *
32
+ * @category InlineNode
33
+ */
34
+ export class Text extends Schema.TaggedClass<Text>()("Text", {
35
+ value: Schema.String
36
+ }) {}
37
+
38
+ /**
39
+ * Inline code span.
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * import { InlineCode } from "@knpkv/atlassian-common/ast"
44
+ *
45
+ * const code = new InlineCode({ value: "const x = 1" })
46
+ * ```
47
+ *
48
+ * @category InlineNode
49
+ */
50
+ export class InlineCode extends Schema.TaggedClass<InlineCode>()("InlineCode", {
51
+ value: Schema.String
52
+ }) {}
53
+
54
+ /**
55
+ * Line break element.
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * import { LineBreak } from "@knpkv/atlassian-common/ast"
60
+ *
61
+ * const br = new LineBreak({})
62
+ * ```
63
+ *
64
+ * @category InlineNode
65
+ */
66
+ export class LineBreak extends Schema.TaggedClass<LineBreak>()("LineBreak", {}) {}
67
+
68
+ /**
69
+ * Unsupported inline element - preserves raw content for round-tripping.
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * import { UnsupportedInline } from "@knpkv/atlassian-common/ast"
74
+ *
75
+ * const unknown = new UnsupportedInline({
76
+ * raw: "<custom-tag>content</custom-tag>",
77
+ * source: "confluence"
78
+ * })
79
+ * ```
80
+ *
81
+ * @category InlineNode
82
+ */
83
+ export class UnsupportedInline extends Schema.TaggedClass<UnsupportedInline>()("UnsupportedInline", {
84
+ raw: Schema.String,
85
+ source: Schema.Literal("confluence", "markdown", "adf")
86
+ }) {}
87
+
88
+ /**
89
+ * Emoticon/emoji element.
90
+ *
91
+ * @example
92
+ * ```typescript
93
+ * import { Emoticon } from "@knpkv/atlassian-common/ast"
94
+ *
95
+ * const emoji = new Emoticon({
96
+ * shortname: ":grinning:",
97
+ * emojiId: "1f600",
98
+ * fallback: "grinning"
99
+ * })
100
+ * ```
101
+ *
102
+ * @category InlineNode
103
+ */
104
+ export class Emoticon extends Schema.TaggedClass<Emoticon>()("Emoticon", {
105
+ shortname: Schema.String,
106
+ emojiId: Schema.String,
107
+ fallback: Schema.String,
108
+ rawSource: RawSource
109
+ }) {}
110
+
111
+ /**
112
+ * User mention element.
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * import { UserMention } from "@knpkv/atlassian-common/ast"
117
+ *
118
+ * const mention = new UserMention({ accountId: "557058:..." })
119
+ * ```
120
+ *
121
+ * @category InlineNode
122
+ */
123
+ export class UserMention extends Schema.TaggedClass<UserMention>()("UserMention", {
124
+ accountId: Schema.String,
125
+ rawSource: RawSource
126
+ }) {}
127
+
128
+ /**
129
+ * Date/time element.
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * import { DateTime } from "@knpkv/atlassian-common/ast"
134
+ *
135
+ * const date = new DateTime({ datetime: "2026-01-01" })
136
+ * ```
137
+ *
138
+ * @category InlineNode
139
+ */
140
+ export class DateTime extends Schema.TaggedClass<DateTime>()("DateTime", {
141
+ datetime: Schema.String,
142
+ rawSource: RawSource
143
+ }) {}
144
+
145
+ /**
146
+ * Underlined text.
147
+ *
148
+ * @category InlineNode
149
+ */
150
+ export class Underline extends Schema.TaggedClass<Underline>()("Underline", {
151
+ children: Schema.suspend(() => Schema.Array(InlineNodeBase))
152
+ }) {}
153
+
154
+ /**
155
+ * Subscript text.
156
+ *
157
+ * @category InlineNode
158
+ */
159
+ export class Subscript extends Schema.TaggedClass<Subscript>()("Subscript", {
160
+ children: Schema.suspend(() => Schema.Array(InlineNodeBase))
161
+ }) {}
162
+
163
+ /**
164
+ * Superscript text.
165
+ *
166
+ * @category InlineNode
167
+ */
168
+ export class Superscript extends Schema.TaggedClass<Superscript>()("Superscript", {
169
+ children: Schema.suspend(() => Schema.Array(InlineNodeBase))
170
+ }) {}
171
+
172
+ /**
173
+ * Strikethrough text.
174
+ *
175
+ * @category InlineNode
176
+ */
177
+ export class Strikethrough extends Schema.TaggedClass<Strikethrough>()("Strikethrough", {
178
+ children: Schema.suspend(() => Schema.Array(InlineNodeBase))
179
+ }) {}
180
+
181
+ /**
182
+ * Colored text with CSS color value.
183
+ *
184
+ * @category InlineNode
185
+ */
186
+ export class ColoredText extends Schema.TaggedClass<ColoredText>()("ColoredText", {
187
+ color: Schema.String,
188
+ children: Schema.suspend(() => Schema.Array(InlineNodeBase))
189
+ }) {}
190
+
191
+ /**
192
+ * Highlighted text with background color.
193
+ *
194
+ * @category InlineNode
195
+ */
196
+ export class Highlight extends Schema.TaggedClass<Highlight>()("Highlight", {
197
+ backgroundColor: Schema.String,
198
+ children: Schema.suspend(() => Schema.Array(InlineNodeBase))
199
+ }) {}
200
+
201
+ // Forward declaration for recursive types
202
+ const InlineNodeBase = Schema.Union(
203
+ Text,
204
+ InlineCode,
205
+ LineBreak,
206
+ Emoticon,
207
+ UserMention,
208
+ DateTime,
209
+ UnsupportedInline
210
+ )
211
+
212
+ /**
213
+ * Inline node children schema - use this for recursive inline content.
214
+ *
215
+ * @category InlineNode
216
+ */
217
+ export const InlineNodeChildren: Schema.Schema<ReadonlyArray<InlineNode>> = Schema.suspend(
218
+ () => Schema.Array(InlineNode)
219
+ )
220
+
221
+ /**
222
+ * Strong/bold text.
223
+ *
224
+ * @example
225
+ * ```typescript
226
+ * import { Strong, Text } from "@knpkv/atlassian-common/ast"
227
+ *
228
+ * const bold = new Strong({ children: [new Text({ value: "important" })] })
229
+ * ```
230
+ *
231
+ * @category InlineNode
232
+ */
233
+ export class Strong extends Schema.TaggedClass<Strong>()("Strong", {
234
+ children: Schema.suspend((): Schema.Schema<ReadonlyArray<InlineNode>> => Schema.Array(InlineNode))
235
+ }) {}
236
+
237
+ /**
238
+ * Emphasized/italic text.
239
+ *
240
+ * @example
241
+ * ```typescript
242
+ * import { Emphasis, Text } from "@knpkv/atlassian-common/ast"
243
+ *
244
+ * const italic = new Emphasis({ children: [new Text({ value: "emphasized" })] })
245
+ * ```
246
+ *
247
+ * @category InlineNode
248
+ */
249
+ export class Emphasis extends Schema.TaggedClass<Emphasis>()("Emphasis", {
250
+ children: Schema.suspend((): Schema.Schema<ReadonlyArray<InlineNode>> => Schema.Array(InlineNode))
251
+ }) {}
252
+
253
+ /**
254
+ * Hyperlink with optional title.
255
+ *
256
+ * @example
257
+ * ```typescript
258
+ * import { Link, Text } from "@knpkv/atlassian-common/ast"
259
+ *
260
+ * const link = new Link({
261
+ * href: "https://example.com",
262
+ * title: "Example",
263
+ * children: [new Text({ value: "Click here" })]
264
+ * })
265
+ * ```
266
+ *
267
+ * @category InlineNode
268
+ */
269
+ export class Link extends Schema.TaggedClass<Link>()("Link", {
270
+ href: Schema.String,
271
+ title: Schema.optional(Schema.String),
272
+ children: Schema.suspend((): Schema.Schema<ReadonlyArray<InlineNode>> => Schema.Array(InlineNode)),
273
+ rawSource: RawSource
274
+ }) {}
275
+
276
+ /**
277
+ * Union of all inline node types.
278
+ *
279
+ * @category InlineNode
280
+ */
281
+ export const InlineNode = Schema.Union(
282
+ Text,
283
+ Strong,
284
+ Emphasis,
285
+ InlineCode,
286
+ Link,
287
+ LineBreak,
288
+ Emoticon,
289
+ UserMention,
290
+ DateTime,
291
+ Underline,
292
+ Subscript,
293
+ Superscript,
294
+ Strikethrough,
295
+ ColoredText,
296
+ Highlight,
297
+ UnsupportedInline
298
+ )
299
+
300
+ /**
301
+ * Type for inline nodes.
302
+ *
303
+ * @category Types
304
+ */
305
+ export type InlineNode =
306
+ | Text
307
+ | Strong
308
+ | Emphasis
309
+ | InlineCode
310
+ | Link
311
+ | LineBreak
312
+ | Emoticon
313
+ | UserMention
314
+ | DateTime
315
+ | Underline
316
+ | Subscript
317
+ | Superscript
318
+ | Strikethrough
319
+ | ColoredText
320
+ | Highlight
321
+ | UnsupportedInline
322
+
323
+ /**
324
+ * Schema type helper for InlineNode.
325
+ *
326
+ * @category Types
327
+ */
328
+ export type InlineNodeSchema = typeof InlineNode
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Confluence macro AST nodes (panels, expand, TOC, code, status).
3
+ *
4
+ * **Mental model**
5
+ *
6
+ * - **Macro = structured metadata + block children**: Each macro wraps Confluence-specific
7
+ * semantics (panel type, code language, status color) around standard block content.
8
+ * - **Serialization-friendly**: Macros carry enough metadata for Markdown comment encoding
9
+ * and ADF reconstruction.
10
+ *
11
+ * @module
12
+ */
13
+ import * as Schema from "effect/Schema"
14
+ import { RawSource, SchemaVersion, SimpleBlockNode } from "./BlockNode.js"
15
+
16
+ /**
17
+ * Supported panel type names.
18
+ *
19
+ * @category MacroNode
20
+ */
21
+ export const PanelTypes = ["info", "warning", "note", "tip", "error", "panel"] as const
22
+
23
+ /**
24
+ * Panel type for info/warning/note macros.
25
+ *
26
+ * @category MacroNode
27
+ */
28
+ export const PanelType = Schema.Literal(...PanelTypes)
29
+
30
+ /**
31
+ * Type for panel type.
32
+ *
33
+ * @category Types
34
+ */
35
+ export type PanelType = Schema.Schema.Type<typeof PanelType>
36
+
37
+ /**
38
+ * Info/Warning/Note panel macro.
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * import { InfoPanel, Paragraph, Text } from "@knpkv/atlassian-common/ast"
43
+ *
44
+ * const panel = {
45
+ * _tag: "InfoPanel" as const,
46
+ * panelType: "warning" as const,
47
+ * title: "Important",
48
+ * children: [new Paragraph({ children: [new Text({ value: "Be careful!" })] })]
49
+ * }
50
+ * ```
51
+ *
52
+ * @category MacroNode
53
+ */
54
+ export const InfoPanel = Schema.Struct({
55
+ _tag: Schema.Literal("InfoPanel"),
56
+ version: SchemaVersion,
57
+ panelType: PanelType,
58
+ title: Schema.optional(Schema.String),
59
+ children: Schema.Array(SimpleBlockNode),
60
+ rawSource: RawSource
61
+ })
62
+
63
+ /**
64
+ * Type for InfoPanel.
65
+ *
66
+ * @category Types
67
+ */
68
+ export type InfoPanel = Schema.Schema.Type<typeof InfoPanel>
69
+
70
+ /**
71
+ * Expand/collapse macro.
72
+ *
73
+ * @category MacroNode
74
+ */
75
+ export const ExpandMacro = Schema.Struct({
76
+ _tag: Schema.Literal("ExpandMacro"),
77
+ version: SchemaVersion,
78
+ title: Schema.optional(Schema.String),
79
+ children: Schema.Array(SimpleBlockNode),
80
+ rawSource: RawSource
81
+ })
82
+
83
+ /**
84
+ * Type for ExpandMacro.
85
+ *
86
+ * @category Types
87
+ */
88
+ export type ExpandMacro = Schema.Schema.Type<typeof ExpandMacro>
89
+
90
+ /**
91
+ * Table of contents macro.
92
+ *
93
+ * @category MacroNode
94
+ */
95
+ export const TocMacro = Schema.Struct({
96
+ _tag: Schema.Literal("TocMacro"),
97
+ version: SchemaVersion,
98
+ minLevel: Schema.optional(Schema.Number),
99
+ maxLevel: Schema.optional(Schema.Number),
100
+ rawSource: RawSource
101
+ })
102
+
103
+ /**
104
+ * Type for TocMacro.
105
+ *
106
+ * @category Types
107
+ */
108
+ export type TocMacro = Schema.Schema.Type<typeof TocMacro>
109
+
110
+ /**
111
+ * Code macro with syntax highlighting.
112
+ *
113
+ * @category MacroNode
114
+ */
115
+ export const CodeMacro = Schema.Struct({
116
+ _tag: Schema.Literal("CodeMacro"),
117
+ version: SchemaVersion,
118
+ language: Schema.optional(Schema.String),
119
+ title: Schema.optional(Schema.String),
120
+ code: Schema.String,
121
+ lineNumbers: Schema.optionalWith(Schema.Boolean, { default: () => false }),
122
+ collapse: Schema.optionalWith(Schema.Boolean, { default: () => false }),
123
+ firstLine: Schema.optional(Schema.Number),
124
+ rawSource: RawSource
125
+ })
126
+
127
+ /**
128
+ * Type for CodeMacro.
129
+ *
130
+ * @category Types
131
+ */
132
+ export type CodeMacro = Schema.Schema.Type<typeof CodeMacro>
133
+
134
+ /**
135
+ * Status macro (colored label).
136
+ *
137
+ * @category MacroNode
138
+ */
139
+ export const StatusMacro = Schema.Struct({
140
+ _tag: Schema.Literal("StatusMacro"),
141
+ version: SchemaVersion,
142
+ text: Schema.String,
143
+ color: Schema.Literal("Grey", "Red", "Yellow", "Green", "Blue"),
144
+ rawSource: RawSource
145
+ })
146
+
147
+ /**
148
+ * Type for StatusMacro.
149
+ *
150
+ * @category Types
151
+ */
152
+ export type StatusMacro = Schema.Schema.Type<typeof StatusMacro>
153
+
154
+ /**
155
+ * Union of all macro node types.
156
+ *
157
+ * @category MacroNode
158
+ */
159
+ export const MacroNode = Schema.Union(
160
+ InfoPanel,
161
+ ExpandMacro,
162
+ TocMacro,
163
+ CodeMacro,
164
+ StatusMacro
165
+ )
166
+
167
+ /**
168
+ * Type for macro nodes.
169
+ *
170
+ * @category Types
171
+ */
172
+ export type MacroNode = InfoPanel | ExpandMacro | TocMacro | CodeMacro | StatusMacro
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Barrel export for Atlassian AST node types and constructors.
3
+ *
4
+ * @module
5
+ */
6
+
7
+ // Inline nodes
8
+ export {
9
+ ColoredText,
10
+ DateTime,
11
+ Emoticon,
12
+ Emphasis,
13
+ Highlight,
14
+ InlineCode,
15
+ InlineNode,
16
+ type InlineNode as InlineNodeType,
17
+ InlineNodeChildren,
18
+ LineBreak,
19
+ Link,
20
+ RawSource as InlineRawSource,
21
+ Strikethrough,
22
+ Strong,
23
+ Subscript,
24
+ Superscript,
25
+ Text,
26
+ Underline,
27
+ UnsupportedInline,
28
+ UserMention
29
+ } from "./InlineNode.js"
30
+
31
+ // Block nodes
32
+ export {
33
+ BlockNode,
34
+ type BlockNode as BlockNodeType,
35
+ BlockQuote,
36
+ CodeBlock,
37
+ Heading,
38
+ Image,
39
+ ImageAttachment,
40
+ type ImageAttachment as ImageAttachmentType,
41
+ List,
42
+ ListItem,
43
+ Paragraph,
44
+ RawSource,
45
+ SchemaVersion,
46
+ SimpleBlockNode,
47
+ Table,
48
+ TableCell,
49
+ TableRow,
50
+ TaskItem,
51
+ type TaskItem as TaskItemType,
52
+ TaskList,
53
+ type TaskList as TaskListType,
54
+ TextAlignment,
55
+ type TextAlignment as TextAlignmentValue,
56
+ ThematicBreak,
57
+ UnsupportedBlock
58
+ } from "./BlockNode.js"
59
+
60
+ // Macro nodes
61
+ export {
62
+ CodeMacro,
63
+ type CodeMacro as CodeMacroType,
64
+ ExpandMacro,
65
+ type ExpandMacro as ExpandMacroType,
66
+ InfoPanel,
67
+ type InfoPanel as InfoPanelType,
68
+ MacroNode,
69
+ type MacroNode as MacroNodeType,
70
+ PanelType,
71
+ type PanelType as PanelTypeValue,
72
+ PanelTypes,
73
+ StatusMacro,
74
+ type StatusMacro as StatusMacroType,
75
+ TocMacro,
76
+ type TocMacro as TocMacroType
77
+ } from "./MacroNode.js"
78
+
79
+ // Document
80
+ export {
81
+ Document,
82
+ type Document as DocumentType,
83
+ DocumentNode,
84
+ type DocumentNode as DocumentNodeType,
85
+ isDocument,
86
+ makeDocument
87
+ } from "./Document.js"
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Atlassian OAuth2 endpoint URLs, scope constants, authorization URL builder, and PKCE.
3
+ *
4
+ * **Mental model**
5
+ *
6
+ * - **Constants + builder**: Endpoint URLs are plain strings; {@link buildAuthUrl}
7
+ * assembles the full authorization URL with audience, scopes, CSRF state, and PKCE.
8
+ * - **Scope sets**: {@link CONFLUENCE_SCOPES} and {@link JIRA_SCOPES} define the
9
+ * minimum permissions for each product's OAuth flow.
10
+ * - **PKCE**: {@link generateCodeVerifier} and {@link computeCodeChallenge} implement
11
+ * RFC 7636 S256 to protect the authorization code grant from interception.
12
+ *
13
+ * @module
14
+ */
15
+ import * as Effect from "effect/Effect"
16
+ import * as Encoding from "effect/Encoding"
17
+
18
+ /**
19
+ * OAuth2 authorization endpoint.
20
+ *
21
+ * @category Endpoints
22
+ */
23
+ export const AUTH_URL = "https://auth.atlassian.com/authorize"
24
+
25
+ /**
26
+ * OAuth2 token endpoint.
27
+ *
28
+ * @category Endpoints
29
+ */
30
+ export const TOKEN_URL = "https://auth.atlassian.com/oauth/token"
31
+
32
+ /**
33
+ * OAuth2 token revocation endpoint.
34
+ *
35
+ * @category Endpoints
36
+ */
37
+ export const REVOKE_URL = "https://auth.atlassian.com/oauth/revoke"
38
+
39
+ /**
40
+ * Accessible resources endpoint (to get cloud IDs).
41
+ *
42
+ * @category Endpoints
43
+ */
44
+ export const RESOURCES_URL = "https://api.atlassian.com/oauth/token/accessible-resources"
45
+
46
+ /**
47
+ * User info endpoint.
48
+ *
49
+ * @category Endpoints
50
+ */
51
+ export const ME_URL = "https://api.atlassian.com/me"
52
+
53
+ /**
54
+ * Confluence scopes for OAuth2.
55
+ *
56
+ * @category Scopes
57
+ */
58
+ export const CONFLUENCE_SCOPES = [
59
+ "read:page:confluence",
60
+ "write:page:confluence",
61
+ "delete:page:confluence",
62
+ "read:me",
63
+ "offline_access"
64
+ ]
65
+
66
+ /**
67
+ * Jira scopes for OAuth2.
68
+ *
69
+ * @category Scopes
70
+ */
71
+ export const JIRA_SCOPES = [
72
+ "read:jira-work",
73
+ "write:jira-work",
74
+ "read:jira-user",
75
+ "manage:jira-project",
76
+ "manage:jira-configuration",
77
+ "read:me",
78
+ "offline_access"
79
+ ]
80
+
81
+ /**
82
+ * Options for building OAuth2 authorization URL.
83
+ *
84
+ * @category Types
85
+ */
86
+ export interface BuildAuthUrlOptions {
87
+ /** OAuth2 client ID */
88
+ readonly clientId: string
89
+ /** State parameter for CSRF protection */
90
+ readonly state: string
91
+ /** Local callback server port */
92
+ readonly port: number
93
+ /** OAuth2 scopes */
94
+ readonly scopes: ReadonlyArray<string>
95
+ /** PKCE code_challenge (S256). Omit to skip PKCE. */
96
+ readonly codeChallenge?: string | undefined
97
+ }
98
+
99
+ /**
100
+ * Build OAuth2 authorization URL.
101
+ *
102
+ * @category Utilities
103
+ */
104
+ export const buildAuthUrl = (options: BuildAuthUrlOptions): string => {
105
+ const params = new URLSearchParams({
106
+ audience: "api.atlassian.com",
107
+ client_id: options.clientId,
108
+ scope: options.scopes.join(" "),
109
+ redirect_uri: `http://localhost:${options.port}/callback`,
110
+ state: options.state,
111
+ response_type: "code",
112
+ prompt: "consent"
113
+ })
114
+ if (options.codeChallenge) {
115
+ params.set("code_challenge", options.codeChallenge)
116
+ params.set("code_challenge_method", "S256")
117
+ }
118
+ return `${AUTH_URL}?${params.toString()}`
119
+ }
120
+
121
+ /**
122
+ * Generate a cryptographically random PKCE code verifier (RFC 7636).
123
+ * Uses Web Crypto API (available in Node 18+, Deno, browsers).
124
+ *
125
+ * @category PKCE
126
+ */
127
+ export const generateCodeVerifier = (): string => {
128
+ const bytes = new Uint8Array(32)
129
+ globalThis.crypto.getRandomValues(bytes)
130
+ return Encoding.encodeBase64Url(bytes)
131
+ }
132
+
133
+ /**
134
+ * Compute S256 code challenge from a code verifier (RFC 7636).
135
+ * Uses Web Crypto `subtle.digest` — returns Effect since digest is async.
136
+ *
137
+ * @category PKCE
138
+ */
139
+ export const computeCodeChallenge = (verifier: string): Effect.Effect<string> =>
140
+ Effect.promise(() => globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier))).pipe(
141
+ Effect.map((hash) => Encoding.encodeBase64Url(new Uint8Array(hash)))
142
+ )