@relayfile/adapter-confluence 0.1.0 → 0.1.2
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 +263 -11
- package/dist/__tests__/confluence-adapter.test.js.map +1 -1
- 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 +23 -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 +106 -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/confluence-adapter.d.ts +37 -0
- package/dist/confluence-adapter.d.ts.map +1 -1
- package/dist/confluence-adapter.js +245 -24
- package/dist/confluence-adapter.js.map +1 -1
- 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 +75 -0
- package/dist/layout-prompt.js.map +1 -0
- package/dist/path-mapper.d.ts +65 -2
- package/dist/path-mapper.d.ts.map +1 -1
- package/dist/path-mapper.js +186 -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 +9 -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
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { computeConfluencePath, confluenceByIdAliasPath, confluenceByTitleAliasPath, confluencePageByIdAliasPath, confluencePageByParentAliasPath, confluencePageBySpaceAliasPath, confluencePageByStatePath, confluencePageByTitleAliasPath, confluencePagePath, confluencePagesIndexPath, confluenceProviderRootIndexPath, confluenceSpaceByIdAliasPath, confluenceSpaceByKeyAliasPath, 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
|
+
it('emits a by-key alias path that preserves the space key verbatim', () => {
|
|
82
|
+
assert.equal(confluenceSpaceByKeyAliasPath('ENG'), '/confluence/spaces/by-key/ENG.json');
|
|
83
|
+
assert.equal(confluenceSpaceByKeyAliasPath('Ops Team'), '/confluence/spaces/by-key/Ops%20Team.json');
|
|
84
|
+
});
|
|
85
|
+
it('emits by-space and by-parent alias paths nested under the parent id segment', () => {
|
|
86
|
+
assert.equal(confluencePageBySpaceAliasPath('12345', '98765'), '/confluence/pages/by-space/12345/98765.json');
|
|
87
|
+
assert.equal(confluencePageByParentAliasPath('44444', '98765'), '/confluence/pages/by-parent/44444/98765.json');
|
|
88
|
+
});
|
|
89
|
+
it('round-trips by-space/by-parent leaves back to the canonical page id', () => {
|
|
90
|
+
const aliasPath = confluencePageBySpaceAliasPath('12345', '98765');
|
|
91
|
+
const leaf = aliasPath.split('/').pop().replace(/\.json$/u, '');
|
|
92
|
+
assert.equal(extractConfluenceIdFromPathSegment(leaf), '98765');
|
|
93
|
+
const parentAliasPath = confluencePageByParentAliasPath('44444', '98765');
|
|
94
|
+
const parentLeaf = parentAliasPath.split('/').pop().replace(/\.json$/u, '');
|
|
95
|
+
assert.equal(extractConfluenceIdFromPathSegment(parentLeaf), '98765');
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe('extractConfluenceIdFromPathSegment', () => {
|
|
99
|
+
it('decodes both the v2 __ separator and the legacy -- separator', () => {
|
|
100
|
+
assert.equal(extractConfluenceIdFromPathSegment('release-plan__98765'), '98765');
|
|
101
|
+
assert.equal(extractConfluenceIdFromPathSegment('release-plan--98765'), '98765');
|
|
102
|
+
assert.equal(extractConfluenceIdFromPathSegment('98765'), '98765');
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
//# 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"}
|
|
@@ -27,6 +27,24 @@ export declare class ConfluenceAdapter {
|
|
|
27
27
|
}): string;
|
|
28
28
|
computeSemantics(objectType: string, objectId: string, payload: Record<string, unknown>): FileSemantics;
|
|
29
29
|
ingestWebhook(workspaceId: string, event: ConfluenceNormalizedEvent | Record<string, unknown>): Promise<IngestResult>;
|
|
30
|
+
private fanoutDelete;
|
|
31
|
+
private fanoutWrite;
|
|
32
|
+
private computeStalePaths;
|
|
33
|
+
/**
|
|
34
|
+
* Returns the by-* alias paths that should be written alongside the
|
|
35
|
+
* canonical record for an event. Aliases store the same bytes as the
|
|
36
|
+
* canonical path so any one of them resolves to the same JSON. Callers
|
|
37
|
+
* doing bulk materialization (e.g. `materializePageFiles`) reuse this so
|
|
38
|
+
* write-path and read-path stay symmetrical.
|
|
39
|
+
*
|
|
40
|
+
* Collision handling: `by-title` uses the canonical slugifier; when two
|
|
41
|
+
* pages share a title in the same scope, the second write wins (Confluence
|
|
42
|
+
* agents almost never lean on by-title for round-trip, so we keep the
|
|
43
|
+
* primary alias collision-free instead of forcing every reader to know the
|
|
44
|
+
* hash suffix). Callers that need the disambiguated form can compute it
|
|
45
|
+
* explicitly via `confluencePageByTitleAliasPath(title, id, true)`.
|
|
46
|
+
*/
|
|
47
|
+
aliasPathsForEvent(event: ConfluenceNormalizedEvent): string[];
|
|
30
48
|
writeBack(path: string, content: string): import("./types.js").ConfluenceWritebackRequest;
|
|
31
49
|
materializeSpace(space: ConfluenceSpace): {
|
|
32
50
|
path: string;
|
|
@@ -36,6 +54,25 @@ export declare class ConfluenceAdapter {
|
|
|
36
54
|
path: string;
|
|
37
55
|
payload: Record<string, unknown>;
|
|
38
56
|
};
|
|
57
|
+
/**
|
|
58
|
+
* Materialize a page into the canonical path plus its by-* alias paths.
|
|
59
|
+
* Callers performing bulk sync (cloud full-resync) should iterate the
|
|
60
|
+
* returned `paths` and write the same `payload` bytes to each — that's
|
|
61
|
+
* how the runtime contract treats aliases (duplicated bytes, single
|
|
62
|
+
* source of truth at the canonical path).
|
|
63
|
+
*/
|
|
64
|
+
materializePageFiles(page: ConfluencePage): {
|
|
65
|
+
paths: string[];
|
|
66
|
+
payload: Record<string, unknown>;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Materialize a space into the canonical path plus its by-* alias paths.
|
|
70
|
+
* See {@link materializePageFiles} for the bulk-sync contract.
|
|
71
|
+
*/
|
|
72
|
+
materializeSpaceFiles(space: ConfluenceSpace): {
|
|
73
|
+
paths: string[];
|
|
74
|
+
payload: Record<string, unknown>;
|
|
75
|
+
};
|
|
39
76
|
protected normalizeEvent(event: ConfluenceNormalizedEvent | Record<string, unknown>): ConfluenceNormalizedEvent;
|
|
40
77
|
protected pathForEvent(event: ConfluenceNormalizedEvent): string;
|
|
41
78
|
protected isDeleteEvent(event: ConfluenceNormalizedEvent): boolean;
|
|
@@ -1 +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;
|
|
1
|
+
{"version":3,"file":"confluence-adapter.d.ts","sourceRoot":"","sources":["../src/confluence-adapter.ts"],"names":[],"mappings":"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"}
|