@relayfile/adapter-confluence 0.1.0 → 0.1.1
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 +4 -4
- package/dist/__tests__/alias-slug.test.d.ts +2 -0
- package/dist/__tests__/alias-slug.test.d.ts.map +1 -0
- package/dist/__tests__/alias-slug.test.js +19 -0
- package/dist/__tests__/alias-slug.test.js.map +1 -0
- package/dist/__tests__/confluence-adapter.test.js +8 -8
- package/dist/__tests__/index-emission.test.d.ts +2 -0
- package/dist/__tests__/index-emission.test.d.ts.map +1 -0
- package/dist/__tests__/index-emission.test.js +67 -0
- package/dist/__tests__/index-emission.test.js.map +1 -0
- package/dist/__tests__/layout-prompt.test.d.ts +2 -0
- package/dist/__tests__/layout-prompt.test.d.ts.map +1 -0
- package/dist/__tests__/layout-prompt.test.js +18 -0
- package/dist/__tests__/layout-prompt.test.js.map +1 -0
- package/dist/__tests__/path-mapper.test.d.ts +2 -0
- package/dist/__tests__/path-mapper.test.d.ts.map +1 -0
- package/dist/__tests__/path-mapper.test.js +90 -0
- package/dist/__tests__/path-mapper.test.js.map +1 -0
- package/dist/__tests__/webhook-normalizer.test.d.ts +2 -0
- package/dist/__tests__/webhook-normalizer.test.d.ts.map +1 -0
- package/dist/__tests__/webhook-normalizer.test.js +106 -0
- package/dist/__tests__/webhook-normalizer.test.js.map +1 -0
- package/dist/alias-slug.d.ts +9 -0
- package/dist/alias-slug.d.ts.map +1 -0
- package/dist/alias-slug.js +23 -0
- package/dist/alias-slug.js.map +1 -0
- package/dist/index-emitter.d.ts +10 -0
- package/dist/index-emitter.d.ts.map +1 -0
- package/dist/index-emitter.js +26 -0
- package/dist/index-emitter.js.map +1 -0
- package/dist/index.d.ts +12 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -3
- package/dist/index.js.map +1 -1
- package/dist/layout-prompt.d.ts +7 -0
- package/dist/layout-prompt.d.ts.map +1 -0
- package/dist/layout-prompt.js +56 -0
- package/dist/layout-prompt.js.map +1 -0
- package/dist/path-mapper.d.ts +40 -2
- package/dist/path-mapper.d.ts.map +1 -1
- package/dist/path-mapper.js +155 -10
- package/dist/path-mapper.js.map +1 -1
- package/dist/queries.d.ts +22 -2
- package/dist/queries.d.ts.map +1 -1
- package/dist/queries.js +43 -2
- package/dist/queries.js.map +1 -1
- package/dist/resources.js +2 -2
- package/dist/resources.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/dist/webhook-normalizer.d.ts +59 -0
- package/dist/webhook-normalizer.d.ts.map +1 -0
- package/dist/webhook-normalizer.js +469 -0
- package/dist/webhook-normalizer.js.map +1 -0
- package/dist/writeback.d.ts +1 -2
- package/dist/writeback.d.ts.map +1 -1
- package/dist/writeback.js +1 -1
- package/dist/writeback.js.map +1 -1
- package/package.json +22 -2
|
@@ -11,8 +11,8 @@ Resources:
|
|
|
11
11
|
|
|
12
12
|
| Resource | Schema | Create example | ID pattern | What it does |
|
|
13
13
|
|---|---|---|---|---|
|
|
14
|
-
| `/confluence/pages/<id>.json` | `/confluence/pages/.schema.json` | `/confluence/pages/.create.example.json` | `^(?:[A-Za-z0-9_.~-]
|
|
15
|
-
| `/confluence/spaces/{spaceIdOrKey}/pages/<id>.json` | `/confluence/spaces/{spaceIdOrKey}/pages/.schema.json` | `/confluence/spaces/{spaceIdOrKey}/pages/.create.example.json` | `^(?:[A-Za-z0-9_.~-]
|
|
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
16
|
|
|
17
17
|
## Operations
|
|
18
18
|
|
|
@@ -24,8 +24,8 @@ Resources:
|
|
|
24
24
|
| Delete | `rm <id>.json` for canonical ids. |
|
|
25
25
|
|
|
26
26
|
## ID Patterns
|
|
27
|
-
- `/confluence/pages/<id>.json`: `^(?:[A-Za-z0-9_.~-]
|
|
28
|
-
- `/confluence/spaces/{spaceIdOrKey}/pages/<id>.json`: `^(?:[A-Za-z0-9_.~-]
|
|
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
29
|
|
|
30
30
|
## Write field contracts
|
|
31
31
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alias-slug.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/alias-slug.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { describe, it } from 'node:test';
|
|
3
|
+
import { aliasCollisionSuffix, slugifyAlias } from '../alias-slug.js';
|
|
4
|
+
describe('confluence alias slug', () => {
|
|
5
|
+
it('slugging is deterministic, ASCII-folded, and strips traversal characters', () => {
|
|
6
|
+
assert.equal(slugifyAlias('Café ../ Roadmap'), 'cafe-roadmap');
|
|
7
|
+
assert.equal(slugifyAlias('Café ../ Roadmap'), slugifyAlias('Café ../ Roadmap'));
|
|
8
|
+
});
|
|
9
|
+
it('falls back to "untitled" when the input slugs to nothing', () => {
|
|
10
|
+
assert.equal(slugifyAlias('🚀🔥'), 'untitled');
|
|
11
|
+
assert.equal(slugifyAlias(' '), 'untitled');
|
|
12
|
+
});
|
|
13
|
+
it('emits an 8-char hex collision suffix from the id', () => {
|
|
14
|
+
const suffix = aliasCollisionSuffix('page-id-1');
|
|
15
|
+
assert.match(suffix, /^[0-9a-f]{8}$/u);
|
|
16
|
+
assert.equal(suffix, aliasCollisionSuffix('page-id-1'));
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
//# sourceMappingURL=alias-slug.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alias-slug.test.js","sourceRoot":"","sources":["../../src/__tests__/alias-slug.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEtE,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,0EAA0E,EAAE,GAAG,EAAE;QAClF,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,CAAC,EAAE,cAAc,CAAC,CAAC;QAC/D,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,CAAC,EAAE,YAAY,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC;QAC/C,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,MAAM,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,oBAAoB,CAAC,WAAW,CAAC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -31,13 +31,13 @@ function createAdapter(client = createClient()) {
|
|
|
31
31
|
}
|
|
32
32
|
describe('ConfluenceAdapter', () => {
|
|
33
33
|
it('computes deterministic Confluence paths', () => {
|
|
34
|
-
assert.equal(computeConfluencePath('space', '12345', { title: 'Engineering Docs' }), '/confluence/spaces/engineering-
|
|
35
|
-
assert.equal(computeConfluencePath('page', '98765', { title: 'Release Plan', spaceId: '12345' }), '/confluence/spaces/12345/pages/release-
|
|
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
36
|
});
|
|
37
37
|
it('materializes spaces and pages from Nango-style sync records', () => {
|
|
38
38
|
const adapter = createAdapter();
|
|
39
39
|
assert.deepEqual(adapter.materializeSpace({ id: '12345', key: 'ENG', name: 'Engineering' }), {
|
|
40
|
-
path: '/confluence/spaces/
|
|
40
|
+
path: '/confluence/spaces/engineering__12345.json',
|
|
41
41
|
payload: {
|
|
42
42
|
provider: 'confluence',
|
|
43
43
|
objectType: 'space',
|
|
@@ -45,7 +45,7 @@ describe('ConfluenceAdapter', () => {
|
|
|
45
45
|
payload: { id: '12345', key: 'ENG', name: 'Engineering' },
|
|
46
46
|
},
|
|
47
47
|
});
|
|
48
|
-
assert.equal(adapter.materializePage({ id: '98765', title: 'Release Plan', spaceId: '12345' }).path, '/confluence/spaces/12345/pages/release-
|
|
48
|
+
assert.equal(adapter.materializePage({ id: '98765', title: 'Release Plan', spaceId: '12345' }).path, '/confluence/spaces/12345/pages/release-plan__98765.json');
|
|
49
49
|
});
|
|
50
50
|
it('ingests page events with space relations and body comments', async () => {
|
|
51
51
|
const client = createClient();
|
|
@@ -64,7 +64,7 @@ describe('ConfluenceAdapter', () => {
|
|
|
64
64
|
},
|
|
65
65
|
});
|
|
66
66
|
assert.equal(result.filesWritten, 1);
|
|
67
|
-
assert.equal(client.writes[0]?.path, '/confluence/spaces/12345/pages/release-
|
|
67
|
+
assert.equal(client.writes[0]?.path, '/confluence/spaces/12345/pages/release-plan__98765.json');
|
|
68
68
|
assert.deepEqual(client.writes[0]?.semantics?.relations, [
|
|
69
69
|
confluenceSpacePath('12345'),
|
|
70
70
|
]);
|
|
@@ -83,7 +83,7 @@ describe('ConfluenceAdapter', () => {
|
|
|
83
83
|
endpoint: '/wiki/api/v2/pages',
|
|
84
84
|
query: { limit: '100', 'body-format': 'storage', 'space-id': '12345' },
|
|
85
85
|
});
|
|
86
|
-
assert.deepEqual(resolveConfluenceReadRequest('/confluence/pages/release-
|
|
86
|
+
assert.deepEqual(resolveConfluenceReadRequest('/confluence/pages/release-plan__98765.json'), {
|
|
87
87
|
action: 'get_page',
|
|
88
88
|
method: 'GET',
|
|
89
89
|
endpoint: '/wiki/api/v2/pages/98765',
|
|
@@ -107,7 +107,7 @@ describe('ConfluenceAdapter', () => {
|
|
|
107
107
|
});
|
|
108
108
|
});
|
|
109
109
|
it('resolves page updates and increments synced version numbers', () => {
|
|
110
|
-
assert.deepEqual(resolveConfluenceWritebackRequest('/confluence/pages/release-
|
|
110
|
+
assert.deepEqual(resolveConfluenceWritebackRequest('/confluence/pages/release-plan__98765.json', JSON.stringify({
|
|
111
111
|
provider: 'confluence',
|
|
112
112
|
objectType: 'page',
|
|
113
113
|
objectId: '98765',
|
|
@@ -134,7 +134,7 @@ describe('ConfluenceAdapter', () => {
|
|
|
134
134
|
});
|
|
135
135
|
});
|
|
136
136
|
it('resolves page deletes and rejects read-only fields', () => {
|
|
137
|
-
assert.deepEqual(resolveConfluenceDeleteRequest('/confluence/pages/release-
|
|
137
|
+
assert.deepEqual(resolveConfluenceDeleteRequest('/confluence/pages/release-plan__98765.json'), {
|
|
138
138
|
action: 'delete_page',
|
|
139
139
|
method: 'DELETE',
|
|
140
140
|
endpoint: '/wiki/api/v2/pages/98765',
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-emission.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/index-emission.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { describe, it } from 'node:test';
|
|
3
|
+
import { buildConfluenceIndexFile } from '../index-emitter.js';
|
|
4
|
+
import { confluencePagePath, confluenceSpacePath, } from '../path-mapper.js';
|
|
5
|
+
import { confluencePageIndexRow, confluenceSpaceIndexRow } from '../queries.js';
|
|
6
|
+
describe('confluence index emission', () => {
|
|
7
|
+
it('emits deterministic page and space indexes sorted by updated DESC, then id ASC', () => {
|
|
8
|
+
const pageRows = [
|
|
9
|
+
confluencePageIndexRow({
|
|
10
|
+
id: '98765',
|
|
11
|
+
title: 'Release Plan',
|
|
12
|
+
spaceId: '12345',
|
|
13
|
+
status: 'current',
|
|
14
|
+
createdAt: '2026-04-01T08:00:00.000Z',
|
|
15
|
+
}),
|
|
16
|
+
confluencePageIndexRow({
|
|
17
|
+
id: '99999',
|
|
18
|
+
title: 'Draft notes',
|
|
19
|
+
spaceId: '12345',
|
|
20
|
+
status: 'draft',
|
|
21
|
+
createdAt: '2026-04-03T10:00:00.000Z',
|
|
22
|
+
}),
|
|
23
|
+
];
|
|
24
|
+
const spaceRows = [
|
|
25
|
+
confluenceSpaceIndexRow({
|
|
26
|
+
id: '12345',
|
|
27
|
+
key: 'ENG',
|
|
28
|
+
name: 'Engineering',
|
|
29
|
+
createdAt: '2026-04-01T08:00:00.000Z',
|
|
30
|
+
}),
|
|
31
|
+
confluenceSpaceIndexRow({
|
|
32
|
+
id: '67890',
|
|
33
|
+
key: 'OPS',
|
|
34
|
+
name: 'Operations',
|
|
35
|
+
createdAt: '2026-04-03T10:00:00.000Z',
|
|
36
|
+
}),
|
|
37
|
+
];
|
|
38
|
+
const pageIndex = buildConfluenceIndexFile('pages', pageRows);
|
|
39
|
+
const pageIndexAgain = buildConfluenceIndexFile('pages', [...pageRows].reverse());
|
|
40
|
+
const spaceIndex = buildConfluenceIndexFile('spaces', spaceRows);
|
|
41
|
+
assert.deepEqual(pageIndex, pageIndexAgain);
|
|
42
|
+
assert.equal(pageIndex.path, '/confluence/pages/_index.json');
|
|
43
|
+
assert.equal(spaceIndex.path, '/confluence/spaces/_index.json');
|
|
44
|
+
assert.equal(pageIndex.contentType, 'application/json; charset=utf-8');
|
|
45
|
+
assert.deepEqual(JSON.parse(pageIndex.content), [
|
|
46
|
+
{ id: '99999', title: 'Draft notes', updated: '2026-04-03T10:00:00.000Z', spaceId: '12345', status: 'draft' },
|
|
47
|
+
{ id: '98765', title: 'Release Plan', updated: '2026-04-01T08:00:00.000Z', spaceId: '12345', status: 'current' },
|
|
48
|
+
]);
|
|
49
|
+
assert.deepEqual(JSON.parse(spaceIndex.content), [
|
|
50
|
+
{ id: '67890', title: 'Operations', updated: '2026-04-03T10:00:00.000Z', key: 'OPS' },
|
|
51
|
+
{ id: '12345', title: 'Engineering', updated: '2026-04-01T08:00:00.000Z', key: 'ENG' },
|
|
52
|
+
]);
|
|
53
|
+
assert.equal(confluencePagePath('98765'), '/confluence/pages/98765.json');
|
|
54
|
+
assert.equal(confluenceSpacePath('12345'), '/confluence/spaces/12345.json');
|
|
55
|
+
});
|
|
56
|
+
it('emits an empty index when a Confluence bucket has no records', () => {
|
|
57
|
+
const file = buildConfluenceIndexFile('pages', []);
|
|
58
|
+
assert.equal(file.path, '/confluence/pages/_index.json');
|
|
59
|
+
assert.deepEqual(JSON.parse(file.content), []);
|
|
60
|
+
});
|
|
61
|
+
it('re-exports the index and layout helpers from the barrel', async () => {
|
|
62
|
+
const barrel = await import('../index.js');
|
|
63
|
+
assert.equal(barrel.buildConfluenceIndexFile, buildConfluenceIndexFile);
|
|
64
|
+
assert.equal(typeof barrel.confluenceLayoutPromptFile, 'function');
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
//# sourceMappingURL=index-emission.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-emission.test.js","sourceRoot":"","sources":["../../src/__tests__/index-emission.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EACL,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAEhF,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,EAAE,CAAC,gFAAgF,EAAE,GAAG,EAAE;QACxF,MAAM,QAAQ,GAAG;YACf,sBAAsB,CAAC;gBACrB,EAAE,EAAE,OAAO;gBACX,KAAK,EAAE,cAAc;gBACrB,OAAO,EAAE,OAAO;gBAChB,MAAM,EAAE,SAAS;gBACjB,SAAS,EAAE,0BAA0B;aACtC,CAAC;YACF,sBAAsB,CAAC;gBACrB,EAAE,EAAE,OAAO;gBACX,KAAK,EAAE,aAAa;gBACpB,OAAO,EAAE,OAAO;gBAChB,MAAM,EAAE,OAAO;gBACf,SAAS,EAAE,0BAA0B;aACtC,CAAC;SACH,CAAC;QACF,MAAM,SAAS,GAAG;YAChB,uBAAuB,CAAC;gBACtB,EAAE,EAAE,OAAO;gBACX,GAAG,EAAE,KAAK;gBACV,IAAI,EAAE,aAAa;gBACnB,SAAS,EAAE,0BAA0B;aACtC,CAAC;YACF,uBAAuB,CAAC;gBACtB,EAAE,EAAE,OAAO;gBACX,GAAG,EAAE,KAAK;gBACV,IAAI,EAAE,YAAY;gBAClB,SAAS,EAAE,0BAA0B;aACtC,CAAC;SACH,CAAC;QAEF,MAAM,SAAS,GAAG,wBAAwB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC9D,MAAM,cAAc,GAAG,wBAAwB,CAAC,OAAO,EAAE,CAAC,GAAG,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QAClF,MAAM,UAAU,GAAG,wBAAwB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAEjE,MAAM,CAAC,SAAS,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QAC5C,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,+BAA+B,CAAC,CAAC;QAC9D,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,gCAAgC,CAAC,CAAC;QAChE,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,WAAW,EAAE,iCAAiC,CAAC,CAAC;QAEvE,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE;YAC9C,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,0BAA0B,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;YAC7G,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,0BAA0B,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE;SACjH,CAAC,CAAC;QAEH,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE;YAC/C,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,0BAA0B,EAAE,GAAG,EAAE,KAAK,EAAE;YACrF,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,0BAA0B,EAAE,GAAG,EAAE,KAAK,EAAE;SACvF,CAAC,CAAC;QAEH,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,8BAA8B,CAAC,CAAC;QAC1E,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,+BAA+B,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,MAAM,IAAI,GAAG,wBAAwB,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACnD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,+BAA+B,CAAC,CAAC;QACzD,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;QACvE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;QAE3C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,wBAAwB,EAAE,wBAAwB,CAAC,CAAC;QACxE,MAAM,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,0BAA0B,EAAE,UAAU,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout-prompt.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/layout-prompt.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { describe, it } from 'node:test';
|
|
3
|
+
import { confluenceLayoutPromptFile } from '../layout-prompt.js';
|
|
4
|
+
describe('confluence layout prompt', () => {
|
|
5
|
+
it('emits the integration layout guide at the confluence root', () => {
|
|
6
|
+
const file = confluenceLayoutPromptFile();
|
|
7
|
+
assert.equal(file.path, '/confluence/LAYOUT.md');
|
|
8
|
+
assert.equal(file.contentType, 'text/markdown; charset=utf-8');
|
|
9
|
+
assert.match(file.content, /\bls\b/u);
|
|
10
|
+
assert.match(file.content, /__/u);
|
|
11
|
+
assert.match(file.content, /_index\.json/u);
|
|
12
|
+
assert.match(file.content, /\/confluence\/pages\//u);
|
|
13
|
+
assert.match(file.content, /\/confluence\/spaces\//u);
|
|
14
|
+
assert.match(file.content, /by-title/u);
|
|
15
|
+
assert.match(file.content, /by-id/u);
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
//# sourceMappingURL=layout-prompt.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout-prompt.test.js","sourceRoot":"","sources":["../../src/__tests__/layout-prompt.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAEjE,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,IAAI,GAAG,0BAA0B,EAAE,CAAC;QAE1C,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,uBAAuB,CAAC,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,8BAA8B,CAAC,CAAC;QAC/D,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACtC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAClC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;QAC5C,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,wBAAwB,CAAC,CAAC;QACrD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,yBAAyB,CAAC,CAAC;QACtD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-mapper.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/path-mapper.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { computeConfluencePath, confluenceByIdAliasPath, confluenceByTitleAliasPath, confluencePageByIdAliasPath, confluencePageByStatePath, confluencePageByTitleAliasPath, confluencePagePath, confluencePagesIndexPath, confluenceProviderRootIndexPath, confluenceSpaceByIdAliasPath, confluenceSpacePath, confluenceSpacesIndexPath, extractConfluenceIdFromPathSegment, nameWithId, normalizeConfluenceObjectType, normalizeNangoConfluenceModel, parseNameWithId, slugifyStatusName, tryNormalizeConfluenceObjectType, } from '../path-mapper.js';
|
|
4
|
+
describe('confluence path-mapper', () => {
|
|
5
|
+
describe('normalizeConfluenceObjectType', () => {
|
|
6
|
+
it('accepts canonical and plural variants', () => {
|
|
7
|
+
assert.equal(normalizeConfluenceObjectType('page'), 'page');
|
|
8
|
+
assert.equal(normalizeConfluenceObjectType('PAGES'), 'page');
|
|
9
|
+
assert.equal(normalizeConfluenceObjectType('Space'), 'space');
|
|
10
|
+
assert.equal(normalizeConfluenceObjectType('spaces'), 'space');
|
|
11
|
+
});
|
|
12
|
+
it('accepts Nango-style PascalCase model names', () => {
|
|
13
|
+
assert.equal(normalizeNangoConfluenceModel('ConfluencePage'), 'page');
|
|
14
|
+
assert.equal(normalizeNangoConfluenceModel('ConfluenceSpace'), 'space');
|
|
15
|
+
});
|
|
16
|
+
it('throws on unknown types', () => {
|
|
17
|
+
assert.throws(() => normalizeConfluenceObjectType('flarb'));
|
|
18
|
+
assert.equal(tryNormalizeConfluenceObjectType('flarb'), undefined);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
describe('nameWithId', () => {
|
|
22
|
+
it('produces <slug>__<id> for page and space leaves', () => {
|
|
23
|
+
assert.equal(confluencePagePath('98765', 'Release Plan'), '/confluence/pages/release-plan__98765.json');
|
|
24
|
+
assert.equal(confluenceSpacePath('12345', 'Engineering Docs'), '/confluence/spaces/engineering-docs__12345.json');
|
|
25
|
+
});
|
|
26
|
+
it('falls back to <id>.json when the title is missing or slugs to nothing', () => {
|
|
27
|
+
assert.equal(confluencePagePath('98765'), '/confluence/pages/98765.json');
|
|
28
|
+
assert.equal(confluencePagePath('98765', ' '), '/confluence/pages/98765.json');
|
|
29
|
+
assert.equal(confluencePagePath('98765', '{{}}'), '/confluence/pages/98765.json');
|
|
30
|
+
});
|
|
31
|
+
it('emits a space-scoped page path under spaces/<spaceId>/pages', () => {
|
|
32
|
+
assert.equal(computeConfluencePath('page', '98765', { title: 'Release Plan', spaceId: '12345' }), '/confluence/spaces/12345/pages/release-plan__98765.json');
|
|
33
|
+
});
|
|
34
|
+
it('disambiguates collisions with an 8-char hash suffix', () => {
|
|
35
|
+
const seen = new Set();
|
|
36
|
+
const first = nameWithId('Roadmap', 'page-1', { existingNames: seen });
|
|
37
|
+
const second = nameWithId('Roadmap', 'page-2', { existingNames: seen });
|
|
38
|
+
assert.equal(first, 'roadmap__page-1');
|
|
39
|
+
assert.match(second, /^roadmap-[0-9a-f]{8}__page-2$/u);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe('parseNameWithId', () => {
|
|
43
|
+
it('splits <slug>__<id>.json leaves', () => {
|
|
44
|
+
assert.deepEqual(parseNameWithId('release-plan__98765.json'), {
|
|
45
|
+
humanReadable: 'release-plan',
|
|
46
|
+
id: '98765',
|
|
47
|
+
ext: 'json',
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
it('returns a bare id when the leaf has no slug prefix', () => {
|
|
51
|
+
assert.deepEqual(parseNameWithId('98765.json'), {
|
|
52
|
+
humanReadable: null,
|
|
53
|
+
id: '98765',
|
|
54
|
+
ext: 'json',
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
describe('index paths', () => {
|
|
59
|
+
it('returns canonical bucket and root index paths', () => {
|
|
60
|
+
assert.equal(confluencePagesIndexPath(), '/confluence/pages/_index.json');
|
|
61
|
+
assert.equal(confluenceSpacesIndexPath(), '/confluence/spaces/_index.json');
|
|
62
|
+
assert.equal(confluenceProviderRootIndexPath(), '/confluence/_index.json');
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
describe('alias paths', () => {
|
|
66
|
+
it('produces by-id and by-title alias paths for pages and spaces', () => {
|
|
67
|
+
assert.equal(confluencePageByIdAliasPath('98765'), '/confluence/pages/by-id/98765.json');
|
|
68
|
+
assert.equal(confluencePageByTitleAliasPath('Release Plan', '98765'), '/confluence/pages/by-title/release-plan.json');
|
|
69
|
+
assert.equal(confluenceSpaceByIdAliasPath('12345'), '/confluence/spaces/by-id/12345.json');
|
|
70
|
+
assert.equal(confluenceByIdAliasPath('/confluence/spaces', 'ENG'), '/confluence/spaces/by-id/ENG.json');
|
|
71
|
+
assert.equal(confluenceByTitleAliasPath('/confluence/spaces', 'Engineering Docs', '12345'), '/confluence/spaces/by-title/engineering-docs.json');
|
|
72
|
+
});
|
|
73
|
+
it('emits a by-state alias path for canonical page statuses', () => {
|
|
74
|
+
assert.equal(confluencePageByStatePath('current', '98765'), '/confluence/pages/by-state/current/98765.json');
|
|
75
|
+
assert.equal(confluencePageByStatePath('draft', '98765'), '/confluence/pages/by-state/draft/98765.json');
|
|
76
|
+
assert.equal(confluencePageByStatePath('archived', '98765'), '/confluence/pages/by-state/archived/98765.json');
|
|
77
|
+
});
|
|
78
|
+
it('rejects empty status names', () => {
|
|
79
|
+
assert.throws(() => slugifyStatusName(' '));
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
describe('extractConfluenceIdFromPathSegment', () => {
|
|
83
|
+
it('decodes both the v2 __ separator and the legacy -- separator', () => {
|
|
84
|
+
assert.equal(extractConfluenceIdFromPathSegment('release-plan__98765'), '98765');
|
|
85
|
+
assert.equal(extractConfluenceIdFromPathSegment('release-plan--98765'), '98765');
|
|
86
|
+
assert.equal(extractConfluenceIdFromPathSegment('98765'), '98765');
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
//# sourceMappingURL=path-mapper.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-mapper.test.js","sourceRoot":"","sources":["../../src/__tests__/path-mapper.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-normalizer.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/webhook-normalizer.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { createHmac } from 'node:crypto';
|
|
3
|
+
import test from 'node:test';
|
|
4
|
+
import { CONFLUENCE_DELIVERY_HEADER, CONFLUENCE_SIGNATURE_HEADER, assertValidConfluenceWebhookSignature, computeConfluenceWebhookSignature, normalizeConfluenceWebhook, validateConfluenceWebhookSignature, validateConfluenceWebhookTimestamp, } from '../index.js';
|
|
5
|
+
const pagePayload = {
|
|
6
|
+
webhookEvent: 'page_updated',
|
|
7
|
+
timestamp: 1_743_155_200_000,
|
|
8
|
+
webhookId: 'webhook_123',
|
|
9
|
+
page: {
|
|
10
|
+
id: '98765',
|
|
11
|
+
title: 'Release Plan',
|
|
12
|
+
spaceId: '12345',
|
|
13
|
+
status: 'current',
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
test('normalizeConfluenceWebhook canonicalizes Atlassian webhookEvent and extracts subject', () => {
|
|
17
|
+
const normalized = normalizeConfluenceWebhook(pagePayload, {
|
|
18
|
+
[CONFLUENCE_DELIVERY_HEADER]: 'delivery_123',
|
|
19
|
+
'X-Relay-Connection-Id': 'conn_confluence_123',
|
|
20
|
+
'X-Relay-Provider-Config-Key': 'confluence',
|
|
21
|
+
});
|
|
22
|
+
assert.equal(normalized.provider, 'confluence');
|
|
23
|
+
assert.equal(normalized.connectionId, 'conn_confluence_123');
|
|
24
|
+
assert.equal(normalized.providerConfigKey, 'confluence');
|
|
25
|
+
assert.equal(normalized.eventType, 'page.update');
|
|
26
|
+
assert.equal(normalized.objectType, 'page');
|
|
27
|
+
assert.equal(normalized.objectId, '98765');
|
|
28
|
+
assert.equal(normalized.payload.id, '98765');
|
|
29
|
+
assert.deepEqual(normalized.payload._connection, {
|
|
30
|
+
connectionId: 'conn_confluence_123',
|
|
31
|
+
deliveryId: 'delivery_123',
|
|
32
|
+
provider: 'confluence',
|
|
33
|
+
providerConfigKey: 'confluence',
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
test('normalizeConfluenceWebhook handles trashed events as remove and accepts dot-notation eventType', () => {
|
|
37
|
+
const removed = normalizeConfluenceWebhook({
|
|
38
|
+
webhookEvent: 'page_trashed',
|
|
39
|
+
page: { id: '98765', title: 'Release Plan' },
|
|
40
|
+
}, {});
|
|
41
|
+
assert.equal(removed.eventType, 'page.remove');
|
|
42
|
+
const explicit = normalizeConfluenceWebhook({
|
|
43
|
+
eventType: 'space.update',
|
|
44
|
+
space: { id: '12345', name: 'Engineering' },
|
|
45
|
+
}, {});
|
|
46
|
+
assert.equal(explicit.eventType, 'space.update');
|
|
47
|
+
assert.equal(explicit.objectType, 'space');
|
|
48
|
+
assert.equal(explicit.objectId, '12345');
|
|
49
|
+
});
|
|
50
|
+
test('validateConfluenceWebhookSignature accepts the expected HMAC and rejects invalid signatures', () => {
|
|
51
|
+
const rawPayload = JSON.stringify(pagePayload);
|
|
52
|
+
const secret = 'confluence-secret';
|
|
53
|
+
const signature = createHmac('sha256', secret).update(rawPayload).digest('hex');
|
|
54
|
+
const valid = validateConfluenceWebhookSignature(rawPayload, { [CONFLUENCE_SIGNATURE_HEADER]: signature }, secret);
|
|
55
|
+
assert.equal(valid.ok, true);
|
|
56
|
+
const invalid = validateConfluenceWebhookSignature(rawPayload, { [CONFLUENCE_SIGNATURE_HEADER]: 'deadbeef' }, secret);
|
|
57
|
+
assert.equal(invalid.ok, false);
|
|
58
|
+
assert.equal(invalid.reason, 'invalid-signature');
|
|
59
|
+
assert.doesNotThrow(() => assertValidConfluenceWebhookSignature(rawPayload, { [CONFLUENCE_SIGNATURE_HEADER]: signature }, secret));
|
|
60
|
+
});
|
|
61
|
+
test('validateConfluenceWebhookTimestamp enforces freshness', () => {
|
|
62
|
+
const fresh = validateConfluenceWebhookTimestamp(pagePayload, 60_000, 1_743_155_230_000);
|
|
63
|
+
assert.equal(fresh.ok, true);
|
|
64
|
+
const stale = validateConfluenceWebhookTimestamp(pagePayload, 60_000, 1_743_155_400_001);
|
|
65
|
+
assert.equal(stale.ok, false);
|
|
66
|
+
assert.equal(stale.reason, 'stale-timestamp');
|
|
67
|
+
});
|
|
68
|
+
// Atlassian Connect sends events with a `confluence:` prefix. Make sure
|
|
69
|
+
// restored and archived land on the same canonical eventType as the
|
|
70
|
+
// un-prefixed variants — without these aliases the fallback splits the
|
|
71
|
+
// underscore name into `confluence:page.restored` and downstream filters
|
|
72
|
+
// on `page.update` miss the event entirely.
|
|
73
|
+
test('normalizeConfluenceWebhook resolves prefixed page_restored / page_archived to page.update', () => {
|
|
74
|
+
for (const event of ['confluence:page_restored', 'confluence:page_archived']) {
|
|
75
|
+
const normalized = normalizeConfluenceWebhook({ ...pagePayload, webhookEvent: event }, { [CONFLUENCE_DELIVERY_HEADER]: `delivery_${event}` });
|
|
76
|
+
assert.equal(normalized.eventType, 'page.update', `${event} should map to page.update`);
|
|
77
|
+
assert.equal(normalized.objectType, 'page');
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
// Unsupported object types must fail fast. The pre-fix code silently
|
|
81
|
+
// coerced anything that wasn't 'space' to 'page', which masked broken
|
|
82
|
+
// upstream payloads and produced bogus tree writes. Provide an
|
|
83
|
+
// objectId via the top-level `id` so we reach the objectType check
|
|
84
|
+
// rather than the missing-id guard.
|
|
85
|
+
test('normalizeConfluenceWebhook fails fast on unsupported object types', () => {
|
|
86
|
+
assert.throws(() => normalizeConfluenceWebhook({
|
|
87
|
+
webhookEvent: 'comment_created',
|
|
88
|
+
id: '111',
|
|
89
|
+
comment: { id: '111', text: 'hi' },
|
|
90
|
+
}, { [CONFLUENCE_DELIVERY_HEADER]: 'delivery_comment' }), /Unsupported Confluence webhook object type/);
|
|
91
|
+
});
|
|
92
|
+
// HMAC must compute over the provider's raw request body. Accepting a
|
|
93
|
+
// parsed object and JSON.stringify-ing it produced digests that drifted
|
|
94
|
+
// from the provider's signature whenever key ordering or whitespace
|
|
95
|
+
// differed. Require raw bytes (string / Buffer / Uint8Array / ArrayBuffer).
|
|
96
|
+
test('computeConfluenceWebhookSignature rejects parsed object payloads', () => {
|
|
97
|
+
assert.throws(() => computeConfluenceWebhookSignature({ webhookEvent: 'page_created' }, 'secret'), /raw request body/);
|
|
98
|
+
});
|
|
99
|
+
test('computeConfluenceWebhookSignature accepts string and Buffer raw bodies', () => {
|
|
100
|
+
const secret = 'shh';
|
|
101
|
+
const body = '{"webhookEvent":"page_created"}';
|
|
102
|
+
const expected = createHmac('sha256', secret).update(body).digest('hex');
|
|
103
|
+
assert.equal(computeConfluenceWebhookSignature(body, secret), expected);
|
|
104
|
+
assert.equal(computeConfluenceWebhookSignature(Buffer.from(body, 'utf8'), secret), expected);
|
|
105
|
+
});
|
|
106
|
+
//# sourceMappingURL=webhook-normalizer.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-normalizer.test.js","sourceRoot":"","sources":["../../src/__tests__/webhook-normalizer.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mirror of the Linear alias slugifier so Confluence emits identical
|
|
3
|
+
* `<sanitized>__<id>` and `by-title/<slug>.json` conventions advertised in
|
|
4
|
+
* `/confluence/LAYOUT.md`. Returns `untitled` when the input slugs to nothing
|
|
5
|
+
* (emoji-only / punctuation-only titles).
|
|
6
|
+
*/
|
|
7
|
+
export declare function slugifyAlias(input: string): string;
|
|
8
|
+
export declare function aliasCollisionSuffix(id: string): string;
|
|
9
|
+
//# sourceMappingURL=alias-slug.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alias-slug.d.ts","sourceRoot":"","sources":["../src/alias-slug.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUlD;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEvD"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
const COMBINING_MARKS_PATTERN = /[\u0300-\u036f]/g;
|
|
3
|
+
const MAX_ALIAS_SLUG_LENGTH = 80;
|
|
4
|
+
/**
|
|
5
|
+
* Mirror of the Linear alias slugifier so Confluence emits identical
|
|
6
|
+
* `<sanitized>__<id>` and `by-title/<slug>.json` conventions advertised in
|
|
7
|
+
* `/confluence/LAYOUT.md`. Returns `untitled` when the input slugs to nothing
|
|
8
|
+
* (emoji-only / punctuation-only titles).
|
|
9
|
+
*/
|
|
10
|
+
export function slugifyAlias(input) {
|
|
11
|
+
const normalized = input
|
|
12
|
+
.normalize('NFKD')
|
|
13
|
+
.replace(COMBINING_MARKS_PATTERN, '')
|
|
14
|
+
.toLowerCase()
|
|
15
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
16
|
+
.slice(0, MAX_ALIAS_SLUG_LENGTH)
|
|
17
|
+
.replace(/^-+|-+$/g, '');
|
|
18
|
+
return normalized || 'untitled';
|
|
19
|
+
}
|
|
20
|
+
export function aliasCollisionSuffix(id) {
|
|
21
|
+
return createHash('sha256').update(id).digest('hex').slice(0, 8);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=alias-slug.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alias-slug.js","sourceRoot":"","sources":["../src/alias-slug.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,uBAAuB,GAAG,kBAAkB,CAAC;AACnD,MAAM,qBAAqB,GAAG,EAAE,CAAC;AAEjC;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,MAAM,UAAU,GAAG,KAAK;SACrB,SAAS,CAAC,MAAM,CAAC;SACjB,OAAO,CAAC,uBAAuB,EAAE,EAAE,CAAC;SACpC,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,KAAK,CAAC,CAAC,EAAE,qBAAqB,CAAC;SAC/B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAE3B,OAAO,UAAU,IAAI,UAAU,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,EAAU;IAC7C,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACnE,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ConfluencePageIndexRow, ConfluenceSpaceIndexRow } from './queries.js';
|
|
2
|
+
export type ConfluenceIndexBucket = 'pages' | 'spaces';
|
|
3
|
+
export interface ConfluenceIndexFile {
|
|
4
|
+
path: string;
|
|
5
|
+
contentType: 'application/json; charset=utf-8';
|
|
6
|
+
content: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function buildConfluenceIndexFile(bucket: 'pages', rows: ConfluencePageIndexRow[]): ConfluenceIndexFile;
|
|
9
|
+
export declare function buildConfluenceIndexFile(bucket: 'spaces', rows: ConfluenceSpaceIndexRow[]): ConfluenceIndexFile;
|
|
10
|
+
//# sourceMappingURL=index-emitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-emitter.d.ts","sourceRoot":"","sources":["../src/index-emitter.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAA0B,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAE5G,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEvD,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,iCAAiC,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,sBAAsB,EAAE,GAC7B,mBAAmB,CAAC;AACvB,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,QAAQ,EAChB,IAAI,EAAE,uBAAuB,EAAE,GAC9B,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { confluencePagesIndexPath, confluenceSpacesIndexPath, } from './path-mapper.js';
|
|
2
|
+
export function buildConfluenceIndexFile(bucket, rows) {
|
|
3
|
+
const sortedRows = [...rows].sort(compareIndexRows());
|
|
4
|
+
return {
|
|
5
|
+
path: indexPathForBucket(bucket),
|
|
6
|
+
contentType: 'application/json; charset=utf-8',
|
|
7
|
+
content: `${JSON.stringify(sortedRows)}\n`,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function indexPathForBucket(bucket) {
|
|
11
|
+
switch (bucket) {
|
|
12
|
+
case 'pages':
|
|
13
|
+
return confluencePagesIndexPath();
|
|
14
|
+
case 'spaces':
|
|
15
|
+
return confluenceSpacesIndexPath();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function compareIndexRows() {
|
|
19
|
+
return (left, right) => {
|
|
20
|
+
if (left.updated !== right.updated) {
|
|
21
|
+
return right.updated.localeCompare(left.updated);
|
|
22
|
+
}
|
|
23
|
+
return left.id.localeCompare(right.id);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=index-emitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-emitter.js","sourceRoot":"","sources":["../src/index-emitter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,kBAAkB,CAAC;AAmB1B,MAAM,UAAU,wBAAwB,CACtC,MAA6B,EAC7B,IAAmC;IAEnC,MAAM,UAAU,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACtD,OAAO;QACL,IAAI,EAAE,kBAAkB,CAAC,MAAM,CAAC;QAChC,WAAW,EAAE,iCAAiC;QAC9C,OAAO,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI;KAC3C,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,MAA6B;IACvD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,OAAO;YACV,OAAO,wBAAwB,EAAE,CAAC;QACpC,KAAK,QAAQ;YACX,OAAO,yBAAyB,EAAE,CAAC;IACvC,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB;IACvB,OAAO,CAAC,IAA4B,EAAE,KAA6B,EAAU,EAAE;QAC7E,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;YACnC,OAAO,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnD,CAAC;QACD,OAAO,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
export { ConfluenceAdapter, } from './confluence-adapter.js';
|
|
2
2
|
export type { ConnectionProvider, IngestError, IngestResult, ProxyRequest, ProxyResponse, } from './confluence-adapter.js';
|
|
3
|
-
export { CONFLUENCE_OBJECT_TYPES, computeConfluencePath, confluencePagePath, confluenceSpacePath, encodeConfluencePathSegment, extractConfluenceIdFromPathSegment, normalizeConfluenceObjectType, } from './path-mapper.js';
|
|
4
|
-
export {
|
|
5
|
-
export {
|
|
3
|
+
export { CONFLUENCE_OBJECT_TYPES, CONFLUENCE_CANONICAL_PAGE_STATUSES, CONFLUENCE_PATH_ROOT, computeConfluencePath, confluenceByIdAliasPath, confluenceByTitleAliasPath, confluencePageByIdAliasPath, confluencePageByStatePath, confluencePageByTitleAliasPath, confluencePagePath, confluencePagesIndexPath, confluenceProviderRootIndexPath, confluenceSpaceByIdAliasPath, confluenceSpaceByTitleAliasPath, confluenceSpacePath, confluenceSpacesIndexPath, encodeConfluencePathSegment, extractConfluenceIdFromPathSegment, nameWithId, normalizeConfluenceObjectType, normalizeNangoConfluenceModel, parseNameWithId, slugifyStatusName, tryNormalizeConfluenceObjectType, } from './path-mapper.js';
|
|
4
|
+
export type { ConfluencePathObjectType, NameWithIdOptions, ParseNameWithIdResult, } from './path-mapper.js';
|
|
5
|
+
export { aliasCollisionSuffix, slugifyAlias, } from './alias-slug.js';
|
|
6
|
+
export { confluenceLayoutPromptFile, CONFLUENCE_LAYOUT_PROMPT, } from './layout-prompt.js';
|
|
7
|
+
export { buildConfluenceIndexFile, } from './index-emitter.js';
|
|
8
|
+
export type { ConfluenceIndexBucket, ConfluenceIndexFile, } from './index-emitter.js';
|
|
9
|
+
export { CONFLUENCE_API_SPACES_ROUTE, confluencePageIndexRow, confluenceSpaceIndexRow, getConfluencePageHumanReadable, getConfluenceSpaceHumanReadable, resolveConfluenceReadRequest, } from './queries.js';
|
|
10
|
+
export type { ConfluenceBaseIndexRow, ConfluencePageIndexRow, ConfluenceSpaceIndexRow, } from './queries.js';
|
|
11
|
+
export { CONFLUENCE_API_PAGES_ROUTE, } from './types.js';
|
|
6
12
|
export type * from './types.js';
|
|
13
|
+
export { ReadOnlyFieldError, resolveConfluenceDeleteRequest, resolveConfluenceWritebackRequest, } from './writeback.js';
|
|
14
|
+
export { assertValidConfluenceWebhookSignature, computeConfluenceWebhookSignature, CONFLUENCE_DELIVERY_HEADER, CONFLUENCE_EVENT_HEADER, CONFLUENCE_PROVIDER, CONFLUENCE_SIGNATURE_HEADER, extractConfluenceConnectionMetadata, extractConfluenceEventType, extractConfluenceObjectId, extractConfluenceObjectType, normalizeConfluenceWebhook, parseConfluenceWebhookPayload, validateConfluenceWebhookSignature, validateConfluenceWebhookTimestamp, } from './webhook-normalizer.js';
|
|
15
|
+
export type { ConfluenceWebhookConnectionMetadata, ConfluenceWebhookHeaders, ConfluenceWebhookSignatureValidationResult, ConfluenceWebhookTimestampValidationResult, } from './webhook-normalizer.js';
|
|
7
16
|
export * from './resources.js';
|
|
8
17
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,GAClB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,GAClB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,uBAAuB,EACvB,kCAAkC,EAClC,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,EAC1B,2BAA2B,EAC3B,yBAAyB,EACzB,8BAA8B,EAC9B,kBAAkB,EAClB,wBAAwB,EACxB,+BAA+B,EAC/B,4BAA4B,EAC5B,+BAA+B,EAC/B,mBAAmB,EACnB,yBAAyB,EACzB,2BAA2B,EAC3B,kCAAkC,EAClC,UAAU,EACV,6BAA6B,EAC7B,6BAA6B,EAC7B,eAAe,EACf,iBAAiB,EACjB,gCAAgC,GACjC,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,wBAAwB,EACxB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,oBAAoB,EACpB,YAAY,GACb,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,wBAAwB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,2BAA2B,EAC3B,sBAAsB,EACtB,uBAAuB,EACvB,8BAA8B,EAC9B,+BAA+B,EAC/B,4BAA4B,GAC7B,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,sBAAsB,EACtB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,0BAA0B,GAC3B,MAAM,YAAY,CAAC;AACpB,mBAAmB,YAAY,CAAC;AAEhC,OAAO,EACL,kBAAkB,EAClB,8BAA8B,EAC9B,iCAAiC,GAClC,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,qCAAqC,EACrC,iCAAiC,EACjC,0BAA0B,EAC1B,uBAAuB,EACvB,mBAAmB,EACnB,2BAA2B,EAC3B,mCAAmC,EACnC,0BAA0B,EAC1B,yBAAyB,EACzB,2BAA2B,EAC3B,0BAA0B,EAC1B,6BAA6B,EAC7B,kCAAkC,EAClC,kCAAkC,GACnC,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,mCAAmC,EACnC,wBAAwB,EACxB,0CAA0C,EAC1C,0CAA0C,GAC3C,MAAM,yBAAyB,CAAC;AAEjC,cAAc,gBAAgB,CAAC"}
|