@relayfile/adapter-confluence 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/discovery/confluence/.adapter.md +72 -0
- package/discovery/confluence/pages/.create.example.json +5 -0
- package/discovery/confluence/pages/.schema.json +171 -0
- package/discovery/confluence/spaces/{spaceIdOrKey}/pages/.create.example.json +4 -0
- package/discovery/confluence/spaces/{spaceIdOrKey}/pages/.schema.json +166 -0
- package/dist/__tests__/confluence-adapter.test.d.ts +2 -0
- package/dist/__tests__/confluence-adapter.test.d.ts.map +1 -0
- package/dist/__tests__/confluence-adapter.test.js +150 -0
- package/dist/__tests__/confluence-adapter.test.js.map +1 -0
- package/dist/confluence-adapter.d.ts +44 -0
- package/dist/confluence-adapter.d.ts.map +1 -0
- package/dist/confluence-adapter.js +218 -0
- package/dist/confluence-adapter.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/path-mapper.d.ts +12 -0
- package/dist/path-mapper.d.ts.map +1 -0
- package/dist/path-mapper.js +65 -0
- package/dist/path-mapper.js.map +1 -0
- package/dist/queries.d.ts +5 -0
- package/dist/queries.d.ts.map +1 -0
- package/dist/queries.js +72 -0
- package/dist/queries.js.map +1 -0
- package/dist/resources.d.ts +25 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +23 -0
- package/dist/resources.js.map +1 -0
- package/dist/types.d.ts +109 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/dist/writeback.d.ts +6 -0
- package/dist/writeback.d.ts.map +1 -0
- package/dist/writeback.js +214 -0
- package/dist/writeback.js.map +1 -0
- package/package.json +75 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Confluence adapter
|
|
2
|
+
|
|
3
|
+
The Confluence adapter exposes spaces and pages under `/confluence`, with writeback routes for creating, updating, and deleting pages.
|
|
4
|
+
|
|
5
|
+
Read-only mounts:
|
|
6
|
+
- `/confluence/spaces/<spaceIdOrKey>.json` - Space records.
|
|
7
|
+
- `/confluence/pages/<pageId>.json` - Flat page records.
|
|
8
|
+
- `/confluence/spaces/<spaceIdOrKey>/pages/<pageId>.json` - Space-scoped page records.
|
|
9
|
+
|
|
10
|
+
Resources:
|
|
11
|
+
|
|
12
|
+
| Resource | Schema | Create example | ID pattern | What it does |
|
|
13
|
+
|---|---|---|---|---|
|
|
14
|
+
| `/confluence/pages/<id>.json` | `/confluence/pages/.schema.json` | `/confluence/pages/.create.example.json` | `^(?:[A-Za-z0-9_.~-]+--)?\d+$` | Creates a Confluence page when `spaceId` is supplied in the document. |
|
|
15
|
+
| `/confluence/spaces/{spaceIdOrKey}/pages/<id>.json` | `/confluence/spaces/{spaceIdOrKey}/pages/.schema.json` | `/confluence/spaces/{spaceIdOrKey}/pages/.create.example.json` | `^(?:[A-Za-z0-9_.~-]+--)?\d+$` | Creates a Confluence page in the space named by the path. |
|
|
16
|
+
|
|
17
|
+
## Operations
|
|
18
|
+
|
|
19
|
+
| To... | Do... |
|
|
20
|
+
|---|---|
|
|
21
|
+
| Read | `cat <id>.json` |
|
|
22
|
+
| Edit | Write a partial JSON object to `<id>.json`. Only included mutable fields PATCH; fields marked `readOnly` in `.schema.json` are rejected. |
|
|
23
|
+
| Create | Write JSON to any non-canonical filename such as `create request.json`. The adapter creates the record at `<real-id>.json` and rewrites the draft as `{ "created": "<real-id>", "path": "<resource>/<real-id>.json", "url": "<provider-url>" }`. |
|
|
24
|
+
| Delete | `rm <id>.json` for canonical ids. |
|
|
25
|
+
|
|
26
|
+
## ID Patterns
|
|
27
|
+
- `/confluence/pages/<id>.json`: `^(?:[A-Za-z0-9_.~-]+--)?\d+$`. Filenames that do not match this pattern are treated as create drafts.
|
|
28
|
+
- `/confluence/spaces/{spaceIdOrKey}/pages/<id>.json`: `^(?:[A-Za-z0-9_.~-]+--)?\d+$`. Filenames that do not match this pattern are treated as create drafts.
|
|
29
|
+
|
|
30
|
+
## Write field contracts
|
|
31
|
+
|
|
32
|
+
### Create Confluence page
|
|
33
|
+
|
|
34
|
+
Resource: `/confluence/pages/<id>.json`
|
|
35
|
+
Schema: `/confluence/pages/.schema.json`
|
|
36
|
+
Create example: `/confluence/pages/.create.example.json`
|
|
37
|
+
Required fields: `title`, `spaceId`, `body`.
|
|
38
|
+
Optional fields: `status`, `parentId`, `version`.
|
|
39
|
+
|
|
40
|
+
Fields:
|
|
41
|
+
|
|
42
|
+
- `title` (required, string) - Page title.
|
|
43
|
+
- `spaceId` (required, string) - Confluence space id.
|
|
44
|
+
- `status` (optional, enum) - Page status. Defaults to current. Allowed values: `current`, `draft`.
|
|
45
|
+
- `parentId` (optional, string) - Optional parent page id.
|
|
46
|
+
- `body` (required, one of string, object) - Confluence page body as a storage-format string or a body object with `value`/`representation` or `storage.value`.
|
|
47
|
+
- `version` (optional, object) - Optional synced version object. Updates increment `version.number` when present.
|
|
48
|
+
- `version.number` (optional, integer) - Current Confluence version number.
|
|
49
|
+
- `version.message` (optional, string) - Version message.
|
|
50
|
+
- `version.minorEdit` (optional, boolean) - Whether the update is a minor edit.
|
|
51
|
+
|
|
52
|
+
### Create Confluence space page
|
|
53
|
+
|
|
54
|
+
Resource: `/confluence/spaces/{spaceIdOrKey}/pages/<id>.json`
|
|
55
|
+
Schema: `/confluence/spaces/{spaceIdOrKey}/pages/.schema.json`
|
|
56
|
+
Create example: `/confluence/spaces/{spaceIdOrKey}/pages/.create.example.json`
|
|
57
|
+
Required fields: `title`, `body`.
|
|
58
|
+
Optional fields: `status`, `parentId`, `version`.
|
|
59
|
+
|
|
60
|
+
Fields:
|
|
61
|
+
|
|
62
|
+
- `title` (required, string) - Page title.
|
|
63
|
+
- `status` (optional, enum) - Page status. Defaults to current. Allowed values: `current`, `draft`.
|
|
64
|
+
- `parentId` (optional, string) - Optional parent page id.
|
|
65
|
+
- `body` (required, one of string, object) - Confluence page body as a storage-format string or a body object with `value`/`representation` or `storage.value`.
|
|
66
|
+
- `version` (optional, object) - Optional synced version object. Updates increment `version.number` when present.
|
|
67
|
+
- `version.number` (optional, integer) - Current Confluence version number.
|
|
68
|
+
- `version.message` (optional, string) - Version message.
|
|
69
|
+
- `version.minorEdit` (optional, boolean) - Whether the update is a minor edit.
|
|
70
|
+
|
|
71
|
+
## Create Examples
|
|
72
|
+
Read the resource `.schema.json` first, then use the sibling `.create.example.json` as a minimal create document. The example intentionally omits read-only fields.
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "Confluence page",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"required": [
|
|
6
|
+
"title",
|
|
7
|
+
"spaceId",
|
|
8
|
+
"body"
|
|
9
|
+
],
|
|
10
|
+
"properties": {
|
|
11
|
+
"title": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"description": "Page title.",
|
|
14
|
+
"minLength": 1
|
|
15
|
+
},
|
|
16
|
+
"spaceId": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"description": "Confluence space id."
|
|
19
|
+
},
|
|
20
|
+
"status": {
|
|
21
|
+
"enum": [
|
|
22
|
+
"current",
|
|
23
|
+
"draft"
|
|
24
|
+
],
|
|
25
|
+
"description": "Page status. Defaults to current."
|
|
26
|
+
},
|
|
27
|
+
"parentId": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"description": "Optional parent page id."
|
|
30
|
+
},
|
|
31
|
+
"body": {
|
|
32
|
+
"description": "Confluence page body as a storage-format string or a body object with `value`/`representation` or `storage.value`.",
|
|
33
|
+
"oneOf": [
|
|
34
|
+
{
|
|
35
|
+
"type": "string",
|
|
36
|
+
"minLength": 1
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"type": "object",
|
|
40
|
+
"additionalProperties": true,
|
|
41
|
+
"required": [
|
|
42
|
+
"value",
|
|
43
|
+
"representation"
|
|
44
|
+
],
|
|
45
|
+
"properties": {
|
|
46
|
+
"value": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"minLength": 1
|
|
49
|
+
},
|
|
50
|
+
"representation": {
|
|
51
|
+
"type": "string",
|
|
52
|
+
"minLength": 1
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"type": "object",
|
|
58
|
+
"additionalProperties": true,
|
|
59
|
+
"required": [
|
|
60
|
+
"storage"
|
|
61
|
+
],
|
|
62
|
+
"properties": {
|
|
63
|
+
"storage": {
|
|
64
|
+
"type": "object",
|
|
65
|
+
"additionalProperties": true,
|
|
66
|
+
"required": [
|
|
67
|
+
"value"
|
|
68
|
+
],
|
|
69
|
+
"properties": {
|
|
70
|
+
"value": {
|
|
71
|
+
"type": "string",
|
|
72
|
+
"minLength": 1
|
|
73
|
+
},
|
|
74
|
+
"representation": {
|
|
75
|
+
"type": "string"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
},
|
|
83
|
+
"version": {
|
|
84
|
+
"type": "object",
|
|
85
|
+
"description": "Optional synced version object. Updates increment `version.number` when present.",
|
|
86
|
+
"properties": {
|
|
87
|
+
"number": {
|
|
88
|
+
"type": "integer",
|
|
89
|
+
"description": "Current Confluence version number.",
|
|
90
|
+
"minimum": 1
|
|
91
|
+
},
|
|
92
|
+
"message": {
|
|
93
|
+
"type": "string",
|
|
94
|
+
"description": "Version message."
|
|
95
|
+
},
|
|
96
|
+
"minorEdit": {
|
|
97
|
+
"type": "boolean",
|
|
98
|
+
"description": "Whether the update is a minor edit."
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
"additionalProperties": true
|
|
102
|
+
},
|
|
103
|
+
"id": {
|
|
104
|
+
"type": "string",
|
|
105
|
+
"description": "Provider canonical record id.",
|
|
106
|
+
"readOnly": true
|
|
107
|
+
},
|
|
108
|
+
"createdAt": {
|
|
109
|
+
"type": "string",
|
|
110
|
+
"format": "date-time",
|
|
111
|
+
"description": "Provider creation timestamp.",
|
|
112
|
+
"readOnly": true
|
|
113
|
+
},
|
|
114
|
+
"updatedAt": {
|
|
115
|
+
"type": "string",
|
|
116
|
+
"format": "date-time",
|
|
117
|
+
"description": "Provider last update timestamp.",
|
|
118
|
+
"readOnly": true
|
|
119
|
+
},
|
|
120
|
+
"url": {
|
|
121
|
+
"type": "string",
|
|
122
|
+
"format": "uri",
|
|
123
|
+
"description": "Provider URL for the record.",
|
|
124
|
+
"readOnly": true
|
|
125
|
+
},
|
|
126
|
+
"identifier": {
|
|
127
|
+
"type": "string",
|
|
128
|
+
"description": "Provider human-readable identifier or key.",
|
|
129
|
+
"readOnly": true
|
|
130
|
+
},
|
|
131
|
+
"provider": {
|
|
132
|
+
"type": "string",
|
|
133
|
+
"description": "Relayfile provider name.",
|
|
134
|
+
"readOnly": true
|
|
135
|
+
},
|
|
136
|
+
"objectType": {
|
|
137
|
+
"type": "string",
|
|
138
|
+
"description": "Relayfile object type.",
|
|
139
|
+
"readOnly": true
|
|
140
|
+
},
|
|
141
|
+
"objectId": {
|
|
142
|
+
"type": "string",
|
|
143
|
+
"description": "Relayfile object id.",
|
|
144
|
+
"readOnly": true
|
|
145
|
+
},
|
|
146
|
+
"workspaceId": {
|
|
147
|
+
"type": "string",
|
|
148
|
+
"description": "Relayfile workspace id.",
|
|
149
|
+
"readOnly": true
|
|
150
|
+
},
|
|
151
|
+
"connectionId": {
|
|
152
|
+
"type": "string",
|
|
153
|
+
"description": "Relayfile connection id.",
|
|
154
|
+
"readOnly": true
|
|
155
|
+
},
|
|
156
|
+
"_webhook": {
|
|
157
|
+
"type": "object",
|
|
158
|
+
"description": "Provider webhook metadata captured during sync.",
|
|
159
|
+
"readOnly": true,
|
|
160
|
+
"additionalProperties": true
|
|
161
|
+
},
|
|
162
|
+
"_connection": {
|
|
163
|
+
"type": "object",
|
|
164
|
+
"description": "Relayfile connection metadata captured during sync.",
|
|
165
|
+
"readOnly": true,
|
|
166
|
+
"additionalProperties": true
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
"additionalProperties": false,
|
|
170
|
+
"description": "Full resource record schema. Fields marked readOnly are synced from the provider and cannot be written by agents."
|
|
171
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "Confluence space page",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"required": [
|
|
6
|
+
"title",
|
|
7
|
+
"body"
|
|
8
|
+
],
|
|
9
|
+
"properties": {
|
|
10
|
+
"title": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"description": "Page title.",
|
|
13
|
+
"minLength": 1
|
|
14
|
+
},
|
|
15
|
+
"status": {
|
|
16
|
+
"enum": [
|
|
17
|
+
"current",
|
|
18
|
+
"draft"
|
|
19
|
+
],
|
|
20
|
+
"description": "Page status. Defaults to current."
|
|
21
|
+
},
|
|
22
|
+
"parentId": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "Optional parent page id."
|
|
25
|
+
},
|
|
26
|
+
"body": {
|
|
27
|
+
"description": "Confluence page body as a storage-format string or a body object with `value`/`representation` or `storage.value`.",
|
|
28
|
+
"oneOf": [
|
|
29
|
+
{
|
|
30
|
+
"type": "string",
|
|
31
|
+
"minLength": 1
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"type": "object",
|
|
35
|
+
"additionalProperties": true,
|
|
36
|
+
"required": [
|
|
37
|
+
"value",
|
|
38
|
+
"representation"
|
|
39
|
+
],
|
|
40
|
+
"properties": {
|
|
41
|
+
"value": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"minLength": 1
|
|
44
|
+
},
|
|
45
|
+
"representation": {
|
|
46
|
+
"type": "string",
|
|
47
|
+
"minLength": 1
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"type": "object",
|
|
53
|
+
"additionalProperties": true,
|
|
54
|
+
"required": [
|
|
55
|
+
"storage"
|
|
56
|
+
],
|
|
57
|
+
"properties": {
|
|
58
|
+
"storage": {
|
|
59
|
+
"type": "object",
|
|
60
|
+
"additionalProperties": true,
|
|
61
|
+
"required": [
|
|
62
|
+
"value"
|
|
63
|
+
],
|
|
64
|
+
"properties": {
|
|
65
|
+
"value": {
|
|
66
|
+
"type": "string",
|
|
67
|
+
"minLength": 1
|
|
68
|
+
},
|
|
69
|
+
"representation": {
|
|
70
|
+
"type": "string"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
},
|
|
78
|
+
"version": {
|
|
79
|
+
"type": "object",
|
|
80
|
+
"description": "Optional synced version object. Updates increment `version.number` when present.",
|
|
81
|
+
"properties": {
|
|
82
|
+
"number": {
|
|
83
|
+
"type": "integer",
|
|
84
|
+
"description": "Current Confluence version number.",
|
|
85
|
+
"minimum": 1
|
|
86
|
+
},
|
|
87
|
+
"message": {
|
|
88
|
+
"type": "string",
|
|
89
|
+
"description": "Version message."
|
|
90
|
+
},
|
|
91
|
+
"minorEdit": {
|
|
92
|
+
"type": "boolean",
|
|
93
|
+
"description": "Whether the update is a minor edit."
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"additionalProperties": true
|
|
97
|
+
},
|
|
98
|
+
"id": {
|
|
99
|
+
"type": "string",
|
|
100
|
+
"description": "Provider canonical record id.",
|
|
101
|
+
"readOnly": true
|
|
102
|
+
},
|
|
103
|
+
"createdAt": {
|
|
104
|
+
"type": "string",
|
|
105
|
+
"format": "date-time",
|
|
106
|
+
"description": "Provider creation timestamp.",
|
|
107
|
+
"readOnly": true
|
|
108
|
+
},
|
|
109
|
+
"updatedAt": {
|
|
110
|
+
"type": "string",
|
|
111
|
+
"format": "date-time",
|
|
112
|
+
"description": "Provider last update timestamp.",
|
|
113
|
+
"readOnly": true
|
|
114
|
+
},
|
|
115
|
+
"url": {
|
|
116
|
+
"type": "string",
|
|
117
|
+
"format": "uri",
|
|
118
|
+
"description": "Provider URL for the record.",
|
|
119
|
+
"readOnly": true
|
|
120
|
+
},
|
|
121
|
+
"identifier": {
|
|
122
|
+
"type": "string",
|
|
123
|
+
"description": "Provider human-readable identifier or key.",
|
|
124
|
+
"readOnly": true
|
|
125
|
+
},
|
|
126
|
+
"provider": {
|
|
127
|
+
"type": "string",
|
|
128
|
+
"description": "Relayfile provider name.",
|
|
129
|
+
"readOnly": true
|
|
130
|
+
},
|
|
131
|
+
"objectType": {
|
|
132
|
+
"type": "string",
|
|
133
|
+
"description": "Relayfile object type.",
|
|
134
|
+
"readOnly": true
|
|
135
|
+
},
|
|
136
|
+
"objectId": {
|
|
137
|
+
"type": "string",
|
|
138
|
+
"description": "Relayfile object id.",
|
|
139
|
+
"readOnly": true
|
|
140
|
+
},
|
|
141
|
+
"workspaceId": {
|
|
142
|
+
"type": "string",
|
|
143
|
+
"description": "Relayfile workspace id.",
|
|
144
|
+
"readOnly": true
|
|
145
|
+
},
|
|
146
|
+
"connectionId": {
|
|
147
|
+
"type": "string",
|
|
148
|
+
"description": "Relayfile connection id.",
|
|
149
|
+
"readOnly": true
|
|
150
|
+
},
|
|
151
|
+
"_webhook": {
|
|
152
|
+
"type": "object",
|
|
153
|
+
"description": "Provider webhook metadata captured during sync.",
|
|
154
|
+
"readOnly": true,
|
|
155
|
+
"additionalProperties": true
|
|
156
|
+
},
|
|
157
|
+
"_connection": {
|
|
158
|
+
"type": "object",
|
|
159
|
+
"description": "Relayfile connection metadata captured during sync.",
|
|
160
|
+
"readOnly": true,
|
|
161
|
+
"additionalProperties": true
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
"additionalProperties": false,
|
|
165
|
+
"description": "Full resource record schema. Fields marked readOnly are synced from the provider and cannot be written by agents."
|
|
166
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confluence-adapter.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/confluence-adapter.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { ConfluenceAdapter, } from '../confluence-adapter.js';
|
|
4
|
+
import { computeConfluencePath, confluencePagePath, confluenceSpacePath, } from '../path-mapper.js';
|
|
5
|
+
import { resolveConfluenceReadRequest } from '../queries.js';
|
|
6
|
+
import { ReadOnlyFieldError, resolveConfluenceDeleteRequest, resolveConfluenceWritebackRequest, } from '../writeback.js';
|
|
7
|
+
function createClient() {
|
|
8
|
+
return {
|
|
9
|
+
writes: [],
|
|
10
|
+
deletes: [],
|
|
11
|
+
async writeFile(input) {
|
|
12
|
+
this.writes.push(input);
|
|
13
|
+
return { created: true };
|
|
14
|
+
},
|
|
15
|
+
async deleteFile(input) {
|
|
16
|
+
this.deletes.push(input);
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function createAdapter(client = createClient()) {
|
|
21
|
+
const provider = {
|
|
22
|
+
name: 'confluence',
|
|
23
|
+
async proxy() {
|
|
24
|
+
return { status: 200, headers: {}, data: {} };
|
|
25
|
+
},
|
|
26
|
+
async healthCheck() {
|
|
27
|
+
return true;
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
return new ConfluenceAdapter(client, provider, { connectionId: 'conn-confluence' });
|
|
31
|
+
}
|
|
32
|
+
describe('ConfluenceAdapter', () => {
|
|
33
|
+
it('computes deterministic Confluence paths', () => {
|
|
34
|
+
assert.equal(computeConfluencePath('space', '12345', { title: 'Engineering Docs' }), '/confluence/spaces/engineering-docs--12345.json');
|
|
35
|
+
assert.equal(computeConfluencePath('page', '98765', { title: 'Release Plan', spaceId: '12345' }), '/confluence/spaces/12345/pages/release-plan--98765.json');
|
|
36
|
+
});
|
|
37
|
+
it('materializes spaces and pages from Nango-style sync records', () => {
|
|
38
|
+
const adapter = createAdapter();
|
|
39
|
+
assert.deepEqual(adapter.materializeSpace({ id: '12345', key: 'ENG', name: 'Engineering' }), {
|
|
40
|
+
path: '/confluence/spaces/engineering--12345.json',
|
|
41
|
+
payload: {
|
|
42
|
+
provider: 'confluence',
|
|
43
|
+
objectType: 'space',
|
|
44
|
+
objectId: '12345',
|
|
45
|
+
payload: { id: '12345', key: 'ENG', name: 'Engineering' },
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
assert.equal(adapter.materializePage({ id: '98765', title: 'Release Plan', spaceId: '12345' }).path, '/confluence/spaces/12345/pages/release-plan--98765.json');
|
|
49
|
+
});
|
|
50
|
+
it('ingests page events with space relations and body comments', async () => {
|
|
51
|
+
const client = createClient();
|
|
52
|
+
const adapter = createAdapter(client);
|
|
53
|
+
const result = await adapter.ingestWebhook('workspace-1', {
|
|
54
|
+
provider: 'confluence',
|
|
55
|
+
eventType: 'page.updated',
|
|
56
|
+
objectType: 'page',
|
|
57
|
+
objectId: '98765',
|
|
58
|
+
payload: {
|
|
59
|
+
id: '98765',
|
|
60
|
+
title: 'Release Plan',
|
|
61
|
+
status: 'current',
|
|
62
|
+
spaceId: '12345',
|
|
63
|
+
body: { storage: { value: '<p>Ship carefully.</p>', representation: 'storage' } },
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
assert.equal(result.filesWritten, 1);
|
|
67
|
+
assert.equal(client.writes[0]?.path, '/confluence/spaces/12345/pages/release-plan--98765.json');
|
|
68
|
+
assert.deepEqual(client.writes[0]?.semantics?.relations, [
|
|
69
|
+
confluenceSpacePath('12345'),
|
|
70
|
+
]);
|
|
71
|
+
assert.equal(client.writes[0]?.semantics?.comments?.[0], 'Ship carefully.');
|
|
72
|
+
});
|
|
73
|
+
it('resolves Confluence read requests to Cloud REST API v2 paths', () => {
|
|
74
|
+
assert.deepEqual(resolveConfluenceReadRequest('/confluence/pages'), {
|
|
75
|
+
action: 'list_pages',
|
|
76
|
+
method: 'GET',
|
|
77
|
+
endpoint: '/wiki/api/v2/pages',
|
|
78
|
+
query: { limit: '100', 'body-format': 'storage' },
|
|
79
|
+
});
|
|
80
|
+
assert.deepEqual(resolveConfluenceReadRequest('/confluence/spaces/12345/pages'), {
|
|
81
|
+
action: 'list_space_pages',
|
|
82
|
+
method: 'GET',
|
|
83
|
+
endpoint: '/wiki/api/v2/pages',
|
|
84
|
+
query: { limit: '100', 'body-format': 'storage', 'space-id': '12345' },
|
|
85
|
+
});
|
|
86
|
+
assert.deepEqual(resolveConfluenceReadRequest('/confluence/pages/release-plan--98765.json'), {
|
|
87
|
+
action: 'get_page',
|
|
88
|
+
method: 'GET',
|
|
89
|
+
endpoint: '/wiki/api/v2/pages/98765',
|
|
90
|
+
query: { 'body-format': 'storage', 'get-draft': 'true' },
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
it('resolves nested page creates with the space id from the path', () => {
|
|
94
|
+
assert.deepEqual(resolveConfluenceWritebackRequest('/confluence/spaces/12345/pages/draft.json', JSON.stringify({
|
|
95
|
+
title: 'Release Plan',
|
|
96
|
+
body: '<p>Ship carefully.</p>',
|
|
97
|
+
})), {
|
|
98
|
+
action: 'create_page',
|
|
99
|
+
method: 'POST',
|
|
100
|
+
endpoint: '/wiki/api/v2/pages',
|
|
101
|
+
body: {
|
|
102
|
+
spaceId: '12345',
|
|
103
|
+
status: 'current',
|
|
104
|
+
title: 'Release Plan',
|
|
105
|
+
body: { representation: 'storage', value: '<p>Ship carefully.</p>' },
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
it('resolves page updates and increments synced version numbers', () => {
|
|
110
|
+
assert.deepEqual(resolveConfluenceWritebackRequest('/confluence/pages/release-plan--98765.json', JSON.stringify({
|
|
111
|
+
provider: 'confluence',
|
|
112
|
+
objectType: 'page',
|
|
113
|
+
objectId: '98765',
|
|
114
|
+
workspaceId: 'workspace-1',
|
|
115
|
+
payload: {
|
|
116
|
+
title: 'Release Plan',
|
|
117
|
+
status: 'current',
|
|
118
|
+
spaceId: '12345',
|
|
119
|
+
version: { number: 7, message: 'sync update', minorEdit: true },
|
|
120
|
+
body: { storage: { value: '<p>Updated.</p>', representation: 'storage' } },
|
|
121
|
+
},
|
|
122
|
+
})), {
|
|
123
|
+
action: 'update_page',
|
|
124
|
+
method: 'PUT',
|
|
125
|
+
endpoint: '/wiki/api/v2/pages/98765',
|
|
126
|
+
body: {
|
|
127
|
+
id: '98765',
|
|
128
|
+
status: 'current',
|
|
129
|
+
title: 'Release Plan',
|
|
130
|
+
body: { representation: 'storage', value: '<p>Updated.</p>' },
|
|
131
|
+
spaceId: '12345',
|
|
132
|
+
version: { number: 8, message: 'sync update', minorEdit: true },
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
it('resolves page deletes and rejects read-only fields', () => {
|
|
137
|
+
assert.deepEqual(resolveConfluenceDeleteRequest('/confluence/pages/release-plan--98765.json'), {
|
|
138
|
+
action: 'delete_page',
|
|
139
|
+
method: 'DELETE',
|
|
140
|
+
endpoint: '/wiki/api/v2/pages/98765',
|
|
141
|
+
});
|
|
142
|
+
assert.throws(() => resolveConfluenceWritebackRequest('/confluence/pages/draft.json', JSON.stringify({
|
|
143
|
+
id: '98765',
|
|
144
|
+
title: 'Release Plan',
|
|
145
|
+
spaceId: '12345',
|
|
146
|
+
body: '<p>Ship carefully.</p>',
|
|
147
|
+
})), ReadOnlyFieldError);
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
//# sourceMappingURL=confluence-adapter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confluence-adapter.test.js","sourceRoot":"","sources":["../../src/__tests__/confluence-adapter.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ConnectionProvider } from '@relayfile/sdk';
|
|
2
|
+
export type { ConnectionProvider, ProxyRequest, ProxyResponse } from '@relayfile/sdk';
|
|
3
|
+
export type { DeleteFileInput, FileSemantics, RelayFileClientLike, WriteFileInput, WriteFileResult, } from './types.js';
|
|
4
|
+
import { type ConfluenceAdapterConfig, type ConfluenceNormalizedEvent, type ConfluencePage, type ConfluenceSpace, type FileSemantics, type RelayFileClientLike } from './types.js';
|
|
5
|
+
export interface IngestError {
|
|
6
|
+
path: string;
|
|
7
|
+
error: string;
|
|
8
|
+
}
|
|
9
|
+
export interface IngestResult {
|
|
10
|
+
filesWritten: number;
|
|
11
|
+
filesUpdated: number;
|
|
12
|
+
filesDeleted: number;
|
|
13
|
+
paths: string[];
|
|
14
|
+
errors: IngestError[];
|
|
15
|
+
}
|
|
16
|
+
export declare class ConfluenceAdapter {
|
|
17
|
+
protected readonly client: RelayFileClientLike;
|
|
18
|
+
protected readonly provider: ConnectionProvider;
|
|
19
|
+
readonly config: ConfluenceAdapterConfig;
|
|
20
|
+
readonly name = "confluence";
|
|
21
|
+
readonly version = "0.1.0";
|
|
22
|
+
constructor(client: RelayFileClientLike, provider: ConnectionProvider, config?: ConfluenceAdapterConfig);
|
|
23
|
+
supportedEvents(): string[];
|
|
24
|
+
computePath(objectType: string, objectId: string, options?: {
|
|
25
|
+
title?: string;
|
|
26
|
+
spaceId?: string;
|
|
27
|
+
}): string;
|
|
28
|
+
computeSemantics(objectType: string, objectId: string, payload: Record<string, unknown>): FileSemantics;
|
|
29
|
+
ingestWebhook(workspaceId: string, event: ConfluenceNormalizedEvent | Record<string, unknown>): Promise<IngestResult>;
|
|
30
|
+
writeBack(path: string, content: string): import("./types.js").ConfluenceWritebackRequest;
|
|
31
|
+
materializeSpace(space: ConfluenceSpace): {
|
|
32
|
+
path: string;
|
|
33
|
+
payload: Record<string, unknown>;
|
|
34
|
+
};
|
|
35
|
+
materializePage(page: ConfluencePage): {
|
|
36
|
+
path: string;
|
|
37
|
+
payload: Record<string, unknown>;
|
|
38
|
+
};
|
|
39
|
+
protected normalizeEvent(event: ConfluenceNormalizedEvent | Record<string, unknown>): ConfluenceNormalizedEvent;
|
|
40
|
+
protected pathForEvent(event: ConfluenceNormalizedEvent): string;
|
|
41
|
+
protected isDeleteEvent(event: ConfluenceNormalizedEvent): boolean;
|
|
42
|
+
protected renderContent(workspaceId: string, event: ConfluenceNormalizedEvent, deleted: boolean): string;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=confluence-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confluence-adapter.d.ts","sourceRoot":"","sources":["../src/confluence-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzD,YAAY,EAAE,kBAAkB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACtF,YAAY,EACV,eAAe,EACf,aAAa,EACb,mBAAmB,EACnB,cAAc,EACd,eAAe,GAChB,MAAM,YAAY,CAAC;AAOpB,OAAO,EAEL,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EAEzB,MAAM,YAAY,CAAC;AAGpB,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAID,qBAAa,iBAAiB;IAK1B,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,mBAAmB;IAC9C,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB;IAC/C,QAAQ,CAAC,MAAM,EAAE,uBAAuB;IAN1C,QAAQ,CAAC,IAAI,gBAA4B;IACzC,QAAQ,CAAC,OAAO,WAAW;gBAGN,MAAM,EAAE,mBAAmB,EAC3B,QAAQ,EAAE,kBAAkB,EACtC,MAAM,GAAE,uBAA4B;IAG/C,eAAe,IAAI,MAAM,EAAE;IAW3B,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,MAAM;IAI7G,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,aAAa;IAsCjG,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,yBAAyB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC;IAuC3H,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAIvC,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE;IAY5F,eAAe,CAAC,IAAI,EAAE,cAAc,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE;IAYzF,SAAS,CAAC,cAAc,CAAC,KAAK,EAAE,yBAAyB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,yBAAyB;IAgC/G,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,yBAAyB,GAAG,MAAM;IAShE,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,yBAAyB,GAAG,OAAO;IAIlE,SAAS,CAAC,aAAa,CACrB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,yBAAyB,EAChC,OAAO,EAAE,OAAO,GACf,MAAM;CAeV"}
|