@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.
Files changed (66) hide show
  1. package/discovery/confluence/.adapter.md +4 -4
  2. package/dist/__tests__/alias-slug.test.d.ts +2 -0
  3. package/dist/__tests__/alias-slug.test.d.ts.map +1 -0
  4. package/dist/__tests__/alias-slug.test.js +19 -0
  5. package/dist/__tests__/alias-slug.test.js.map +1 -0
  6. package/dist/__tests__/confluence-adapter.test.js +263 -11
  7. package/dist/__tests__/confluence-adapter.test.js.map +1 -1
  8. package/dist/__tests__/index-emission.test.d.ts +2 -0
  9. package/dist/__tests__/index-emission.test.d.ts.map +1 -0
  10. package/dist/__tests__/index-emission.test.js +67 -0
  11. package/dist/__tests__/index-emission.test.js.map +1 -0
  12. package/dist/__tests__/layout-prompt.test.d.ts +2 -0
  13. package/dist/__tests__/layout-prompt.test.d.ts.map +1 -0
  14. package/dist/__tests__/layout-prompt.test.js +23 -0
  15. package/dist/__tests__/layout-prompt.test.js.map +1 -0
  16. package/dist/__tests__/path-mapper.test.d.ts +2 -0
  17. package/dist/__tests__/path-mapper.test.d.ts.map +1 -0
  18. package/dist/__tests__/path-mapper.test.js +106 -0
  19. package/dist/__tests__/path-mapper.test.js.map +1 -0
  20. package/dist/__tests__/webhook-normalizer.test.d.ts +2 -0
  21. package/dist/__tests__/webhook-normalizer.test.d.ts.map +1 -0
  22. package/dist/__tests__/webhook-normalizer.test.js +106 -0
  23. package/dist/__tests__/webhook-normalizer.test.js.map +1 -0
  24. package/dist/alias-slug.d.ts +9 -0
  25. package/dist/alias-slug.d.ts.map +1 -0
  26. package/dist/alias-slug.js +23 -0
  27. package/dist/alias-slug.js.map +1 -0
  28. package/dist/confluence-adapter.d.ts +37 -0
  29. package/dist/confluence-adapter.d.ts.map +1 -1
  30. package/dist/confluence-adapter.js +245 -24
  31. package/dist/confluence-adapter.js.map +1 -1
  32. package/dist/index-emitter.d.ts +10 -0
  33. package/dist/index-emitter.d.ts.map +1 -0
  34. package/dist/index-emitter.js +26 -0
  35. package/dist/index-emitter.js.map +1 -0
  36. package/dist/index.d.ts +12 -3
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +8 -3
  39. package/dist/index.js.map +1 -1
  40. package/dist/layout-prompt.d.ts +7 -0
  41. package/dist/layout-prompt.d.ts.map +1 -0
  42. package/dist/layout-prompt.js +75 -0
  43. package/dist/layout-prompt.js.map +1 -0
  44. package/dist/path-mapper.d.ts +65 -2
  45. package/dist/path-mapper.d.ts.map +1 -1
  46. package/dist/path-mapper.js +186 -10
  47. package/dist/path-mapper.js.map +1 -1
  48. package/dist/queries.d.ts +22 -2
  49. package/dist/queries.d.ts.map +1 -1
  50. package/dist/queries.js +43 -2
  51. package/dist/queries.js.map +1 -1
  52. package/dist/resources.js +2 -2
  53. package/dist/resources.js.map +1 -1
  54. package/dist/types.d.ts +9 -0
  55. package/dist/types.d.ts.map +1 -1
  56. package/dist/types.js +1 -0
  57. package/dist/types.js.map +1 -1
  58. package/dist/webhook-normalizer.d.ts +59 -0
  59. package/dist/webhook-normalizer.d.ts.map +1 -0
  60. package/dist/webhook-normalizer.js +469 -0
  61. package/dist/webhook-normalizer.js.map +1 -0
  62. package/dist/writeback.d.ts +1 -2
  63. package/dist/writeback.d.ts.map +1 -1
  64. package/dist/writeback.js +1 -1
  65. package/dist/writeback.js.map +1 -1
  66. 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_.~-]+--)?\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. |
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_.~-]+--)?\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.
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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=alias-slug.test.d.ts.map
@@ -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"}
@@ -1,7 +1,7 @@
1
1
  import { describe, it } from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import { ConfluenceAdapter, } from '../confluence-adapter.js';
4
- import { computeConfluencePath, confluencePagePath, confluenceSpacePath, } from '../path-mapper.js';
4
+ import { computeConfluencePath, confluencePageByIdAliasPath, confluencePageByParentAliasPath, confluencePageBySpaceAliasPath, confluencePageByStatePath, confluencePageByTitleAliasPath, confluencePagePath, confluenceSpaceByIdAliasPath, confluenceSpaceByKeyAliasPath, confluenceSpaceByTitleAliasPath, confluenceSpacePath, } from '../path-mapper.js';
5
5
  import { resolveConfluenceReadRequest } from '../queries.js';
6
6
  import { ReadOnlyFieldError, resolveConfluenceDeleteRequest, resolveConfluenceWritebackRequest, } from '../writeback.js';
7
7
  function createClient() {
@@ -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-docs--12345.json');
35
- assert.equal(computeConfluencePath('page', '98765', { title: 'Release Plan', spaceId: '12345' }), '/confluence/spaces/12345/pages/release-plan--98765.json');
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/engineering--12345.json',
40
+ path: '/confluence/spaces/engineering__12345.json',
41
41
  payload: {
42
42
  provider: 'confluence',
43
43
  objectType: 'space',
@@ -45,9 +45,9 @@ 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-plan--98765.json');
48
+ assert.equal(adapter.materializePage({ id: '98765', title: 'Release Plan', spaceId: '12345' }).path, '/confluence/spaces/12345/pages/release-plan__98765.json');
49
49
  });
50
- it('ingests page events with space relations and body comments', async () => {
50
+ it('ingests page events with space relations, body comments, and by-* alias fan-out', async () => {
51
51
  const client = createClient();
52
52
  const adapter = createAdapter(client);
53
53
  const result = await adapter.ingestWebhook('workspace-1', {
@@ -60,16 +60,268 @@ describe('ConfluenceAdapter', () => {
60
60
  title: 'Release Plan',
61
61
  status: 'current',
62
62
  spaceId: '12345',
63
+ parentId: '44444',
63
64
  body: { storage: { value: '<p>Ship carefully.</p>', representation: 'storage' } },
64
65
  },
65
66
  });
66
- assert.equal(result.filesWritten, 1);
67
- assert.equal(client.writes[0]?.path, '/confluence/spaces/12345/pages/release-plan--98765.json');
67
+ const canonicalPath = '/confluence/spaces/12345/pages/release-plan__98765.json';
68
+ const expectedAliasPaths = [
69
+ confluencePageByIdAliasPath('98765'),
70
+ confluencePageByTitleAliasPath('Release Plan', '98765'),
71
+ confluencePageByStatePath('current', '98765'),
72
+ confluencePageBySpaceAliasPath('12345', '98765'),
73
+ confluencePageByParentAliasPath('44444', '98765'),
74
+ ];
75
+ // Canonical record + every applicable alias path are written with identical
76
+ // bytes — readers can pick whichever lookup primitive they have.
77
+ assert.equal(result.filesWritten, 1 + expectedAliasPaths.length);
78
+ assert.deepEqual(result.paths, [canonicalPath, ...expectedAliasPaths]);
79
+ const canonicalContent = client.writes.find((write) => write.path === canonicalPath)?.content;
80
+ assert.ok(canonicalContent, 'canonical content must be present');
81
+ for (const aliasPath of expectedAliasPaths) {
82
+ const aliasWrite = client.writes.find((write) => write.path === aliasPath);
83
+ assert.ok(aliasWrite, `alias ${aliasPath} must be written`);
84
+ assert.equal(aliasWrite?.content, canonicalContent, `alias ${aliasPath} bytes must match canonical`);
85
+ }
68
86
  assert.deepEqual(client.writes[0]?.semantics?.relations, [
69
87
  confluenceSpacePath('12345'),
88
+ confluencePagePath('44444'),
70
89
  ]);
71
90
  assert.equal(client.writes[0]?.semantics?.comments?.[0], 'Ship carefully.');
72
91
  });
92
+ it('skips by-title alias when the page title slugs to nothing', async () => {
93
+ const client = createClient();
94
+ const adapter = createAdapter(client);
95
+ await adapter.ingestWebhook('workspace-1', {
96
+ provider: 'confluence',
97
+ eventType: 'page.created',
98
+ objectType: 'page',
99
+ objectId: '11111',
100
+ payload: { id: '11111', title: '🚀🔥', status: 'current', spaceId: '12345' },
101
+ });
102
+ // by-id, by-state, by-space — no by-title, no by-parent.
103
+ const aliasPaths = client.writes.map((write) => write.path).filter((path) => path.includes('/by-'));
104
+ assert.deepEqual(aliasPaths, [
105
+ confluencePageByIdAliasPath('11111'),
106
+ confluencePageByStatePath('current', '11111'),
107
+ confluencePageBySpaceAliasPath('12345', '11111'),
108
+ ]);
109
+ });
110
+ it('emits space by-id, by-title, and by-key aliases on space ingest', async () => {
111
+ const client = createClient();
112
+ const adapter = createAdapter(client);
113
+ await adapter.ingestWebhook('workspace-1', {
114
+ provider: 'confluence',
115
+ eventType: 'space.updated',
116
+ objectType: 'space',
117
+ objectId: '12345',
118
+ payload: { id: '12345', key: 'ENG', name: 'Engineering' },
119
+ });
120
+ const canonicalPath = '/confluence/spaces/engineering__12345.json';
121
+ const expectedAliasPaths = [
122
+ confluenceSpaceByIdAliasPath('12345'),
123
+ confluenceSpaceByTitleAliasPath('Engineering', '12345'),
124
+ confluenceSpaceByKeyAliasPath('ENG'),
125
+ ];
126
+ assert.deepEqual(client.writes.map((write) => write.path), [canonicalPath, ...expectedAliasPaths]);
127
+ });
128
+ it('deletes the canonical path and every alias on a delete event', async () => {
129
+ const client = createClient();
130
+ const adapter = createAdapter(client);
131
+ const result = await adapter.ingestWebhook('workspace-1', {
132
+ provider: 'confluence',
133
+ eventType: 'page.deleted',
134
+ objectType: 'page',
135
+ objectId: '98765',
136
+ payload: { id: '98765', title: 'Release Plan', status: 'current', spaceId: '12345' },
137
+ });
138
+ const canonicalPath = '/confluence/spaces/12345/pages/release-plan__98765.json';
139
+ const expectedAliasPaths = [
140
+ confluencePageByIdAliasPath('98765'),
141
+ confluencePageByTitleAliasPath('Release Plan', '98765'),
142
+ confluencePageByStatePath('current', '98765'),
143
+ confluencePageBySpaceAliasPath('12345', '98765'),
144
+ ];
145
+ assert.equal(result.filesDeleted, 1 + expectedAliasPaths.length);
146
+ assert.deepEqual(client.deletes.map((d) => d.path), [canonicalPath, ...expectedAliasPaths]);
147
+ });
148
+ it('materializePageFiles returns the canonical path plus every applicable alias', () => {
149
+ const adapter = createAdapter();
150
+ const { paths } = adapter.materializePageFiles({
151
+ id: '98765',
152
+ title: 'Release Plan',
153
+ status: 'current',
154
+ spaceId: '12345',
155
+ parentId: '44444',
156
+ });
157
+ assert.deepEqual(paths, [
158
+ '/confluence/spaces/12345/pages/release-plan__98765.json',
159
+ confluencePageByIdAliasPath('98765'),
160
+ confluencePageByTitleAliasPath('Release Plan', '98765'),
161
+ confluencePageByStatePath('current', '98765'),
162
+ confluencePageBySpaceAliasPath('12345', '98765'),
163
+ confluencePageByParentAliasPath('44444', '98765'),
164
+ ]);
165
+ });
166
+ it('materializeSpaceFiles returns the canonical path plus every applicable alias', () => {
167
+ const adapter = createAdapter();
168
+ const { paths } = adapter.materializeSpaceFiles({
169
+ id: '12345',
170
+ key: 'ENG',
171
+ name: 'Engineering',
172
+ });
173
+ assert.deepEqual(paths, [
174
+ '/confluence/spaces/engineering__12345.json',
175
+ confluenceSpaceByIdAliasPath('12345'),
176
+ confluenceSpaceByTitleAliasPath('Engineering', '12345'),
177
+ confluenceSpaceByKeyAliasPath('ENG'),
178
+ ]);
179
+ });
180
+ it('continues fanning out aliases when one writeFile throws and reports the failed path', async () => {
181
+ // A mid-loop throw used to abandon the rest of the fan-out, leaving the
182
+ // canonical record and earlier aliases written but later aliases missing.
183
+ // Now each write is independent: the canonical + the surviving aliases
184
+ // land, the bad path is reported in `errors`, and the caller can retry
185
+ // just that path.
186
+ const failingPath = confluencePageByTitleAliasPath('Release Plan', '98765');
187
+ const client = {
188
+ writes: [],
189
+ deletes: [],
190
+ async writeFile(input) {
191
+ if (input.path === failingPath) {
192
+ throw new Error('synthetic backend error');
193
+ }
194
+ this.writes.push(input);
195
+ return { created: true };
196
+ },
197
+ async deleteFile(input) {
198
+ this.deletes.push(input);
199
+ },
200
+ };
201
+ const adapter = createAdapter(client);
202
+ const result = await adapter.ingestWebhook('workspace-1', {
203
+ provider: 'confluence',
204
+ eventType: 'page.updated',
205
+ objectType: 'page',
206
+ objectId: '98765',
207
+ payload: { id: '98765', title: 'Release Plan', status: 'current', spaceId: '12345' },
208
+ });
209
+ assert.equal(result.errors.length, 1);
210
+ assert.equal(result.errors[0].path, failingPath);
211
+ assert.match(result.errors[0].error, /synthetic backend error/);
212
+ const expectedWrittenPaths = [
213
+ '/confluence/spaces/12345/pages/release-plan__98765.json',
214
+ confluencePageByIdAliasPath('98765'),
215
+ confluencePageByStatePath('current', '98765'),
216
+ confluencePageBySpaceAliasPath('12345', '98765'),
217
+ ];
218
+ assert.deepEqual(client.writes.map((w) => w.path), expectedWrittenPaths);
219
+ assert.deepEqual(result.paths, expectedWrittenPaths);
220
+ });
221
+ it('deletes stale aliases on rename via the by-id reconciliation path', async () => {
222
+ // When an alias-driving field changes (here: title), the prior alias
223
+ // paths (`by-title/release-plan__98765.json` and the old canonical
224
+ // `release-plan__98765.json`) become orphans. Reconciliation reads the
225
+ // stable by-id alias to recover the prior payload, computes the prior
226
+ // alias set, and deletes the diff before writing the new alias set.
227
+ const priorPayload = { id: '98765', title: 'Release Plan', status: 'current', spaceId: '12345' };
228
+ const priorWrapper = {
229
+ provider: 'confluence',
230
+ workspaceId: 'workspace-1',
231
+ objectType: 'page',
232
+ objectId: '98765',
233
+ deleted: false,
234
+ payload: priorPayload,
235
+ connectionId: 'conn-confluence',
236
+ };
237
+ const reads = [];
238
+ const client = {
239
+ writes: [],
240
+ deletes: [],
241
+ async writeFile(input) {
242
+ this.writes.push(input);
243
+ return { updated: true };
244
+ },
245
+ async deleteFile(input) {
246
+ this.deletes.push(input);
247
+ },
248
+ async readFile(input) {
249
+ reads.push(input);
250
+ if (input.path === confluencePageByIdAliasPath('98765')) {
251
+ return { content: JSON.stringify(priorWrapper, null, 2) };
252
+ }
253
+ return null;
254
+ },
255
+ };
256
+ const adapter = createAdapter(client);
257
+ await adapter.ingestWebhook('workspace-1', {
258
+ provider: 'confluence',
259
+ eventType: 'page.updated',
260
+ objectType: 'page',
261
+ objectId: '98765',
262
+ payload: { id: '98765', title: 'Launch Plan', status: 'current', spaceId: '12345' },
263
+ });
264
+ // The reconciliation read targeted the stable by-id path.
265
+ assert.deepEqual(reads, [{ workspaceId: 'workspace-1', path: confluencePageByIdAliasPath('98765') }]);
266
+ // Stale paths from the prior title were deleted: old canonical + old by-title.
267
+ const deletedPaths = new Set(client.deletes.map((d) => d.path));
268
+ assert.ok(deletedPaths.has('/confluence/spaces/12345/pages/release-plan__98765.json'), 'expected old canonical path to be deleted');
269
+ assert.ok(deletedPaths.has(confluencePageByTitleAliasPath('Release Plan', '98765')), 'expected old by-title alias to be deleted');
270
+ // The stable by-id, by-state, by-space aliases are unchanged → not deleted.
271
+ assert.ok(!deletedPaths.has(confluencePageByIdAliasPath('98765')));
272
+ assert.ok(!deletedPaths.has(confluencePageByStatePath('current', '98765')));
273
+ assert.ok(!deletedPaths.has(confluencePageBySpaceAliasPath('12345', '98765')));
274
+ // New canonical + new by-title written.
275
+ const writtenPaths = new Set(client.writes.map((w) => w.path));
276
+ assert.ok(writtenPaths.has('/confluence/spaces/12345/pages/launch-plan__98765.json'));
277
+ assert.ok(writtenPaths.has(confluencePageByTitleAliasPath('Launch Plan', '98765')));
278
+ });
279
+ it('skips reconciliation when client has no readFile (legacy adapters keep working)', async () => {
280
+ // Pre-#69 behavior: clients without readFile see no reconciliation. The
281
+ // adapter must still write the new alias set; it just can't clean up
282
+ // stale aliases. This is the "degrade gracefully" contract.
283
+ const client = createClient(); // no readFile defined
284
+ const adapter = createAdapter(client);
285
+ const result = await adapter.ingestWebhook('workspace-1', {
286
+ provider: 'confluence',
287
+ eventType: 'page.updated',
288
+ objectType: 'page',
289
+ objectId: '98765',
290
+ payload: { id: '98765', title: 'Launch Plan', status: 'current', spaceId: '12345' },
291
+ });
292
+ assert.equal(result.errors.length, 0);
293
+ assert.deepEqual(client.deletes, []);
294
+ assert.ok(client.writes.length > 0);
295
+ });
296
+ it('treats readFile errors as non-fatal and proceeds with the write fan-out', async () => {
297
+ // A 5xx on the reconciliation read must not block the canonical write —
298
+ // stale aliases are a maintenance concern, not a correctness blocker.
299
+ const client = {
300
+ writes: [],
301
+ deletes: [],
302
+ async writeFile(input) {
303
+ this.writes.push(input);
304
+ return { created: true };
305
+ },
306
+ async deleteFile(input) {
307
+ this.deletes.push(input);
308
+ },
309
+ async readFile() {
310
+ throw new Error('synthetic 503 from relayfile');
311
+ },
312
+ };
313
+ const adapter = createAdapter(client);
314
+ const result = await adapter.ingestWebhook('workspace-1', {
315
+ provider: 'confluence',
316
+ eventType: 'page.updated',
317
+ objectType: 'page',
318
+ objectId: '98765',
319
+ payload: { id: '98765', title: 'Launch Plan', status: 'current', spaceId: '12345' },
320
+ });
321
+ assert.equal(result.errors.length, 0);
322
+ assert.deepEqual(client.deletes, []); // no reconciliation deletes attempted
323
+ assert.ok(client.writes.length > 0); // canonical write still landed
324
+ });
73
325
  it('resolves Confluence read requests to Cloud REST API v2 paths', () => {
74
326
  assert.deepEqual(resolveConfluenceReadRequest('/confluence/pages'), {
75
327
  action: 'list_pages',
@@ -83,7 +335,7 @@ describe('ConfluenceAdapter', () => {
83
335
  endpoint: '/wiki/api/v2/pages',
84
336
  query: { limit: '100', 'body-format': 'storage', 'space-id': '12345' },
85
337
  });
86
- assert.deepEqual(resolveConfluenceReadRequest('/confluence/pages/release-plan--98765.json'), {
338
+ assert.deepEqual(resolveConfluenceReadRequest('/confluence/pages/release-plan__98765.json'), {
87
339
  action: 'get_page',
88
340
  method: 'GET',
89
341
  endpoint: '/wiki/api/v2/pages/98765',
@@ -107,7 +359,7 @@ describe('ConfluenceAdapter', () => {
107
359
  });
108
360
  });
109
361
  it('resolves page updates and increments synced version numbers', () => {
110
- assert.deepEqual(resolveConfluenceWritebackRequest('/confluence/pages/release-plan--98765.json', JSON.stringify({
362
+ assert.deepEqual(resolveConfluenceWritebackRequest('/confluence/pages/release-plan__98765.json', JSON.stringify({
111
363
  provider: 'confluence',
112
364
  objectType: 'page',
113
365
  objectId: '98765',
@@ -134,7 +386,7 @@ describe('ConfluenceAdapter', () => {
134
386
  });
135
387
  });
136
388
  it('resolves page deletes and rejects read-only fields', () => {
137
- assert.deepEqual(resolveConfluenceDeleteRequest('/confluence/pages/release-plan--98765.json'), {
389
+ assert.deepEqual(resolveConfluenceDeleteRequest('/confluence/pages/release-plan__98765.json'), {
138
390
  action: 'delete_page',
139
391
  method: 'DELETE',
140
392
  endpoint: '/wiki/api/v2/pages/98765',
@@ -1 +1 @@
1
- {"version":3,"file":"confluence-adapter.test.js","sourceRoot":"","sources":["../../src/__tests__/confluence-adapter.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AAGxC,OAAO,EACL,iBAAiB,GAGlB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,4BAA4B,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EACL,kBAAkB,EAClB,8BAA8B,EAC9B,iCAAiC,GAClC,MAAM,iBAAiB,CAAC;AAOzB,SAAS,YAAY;IACnB,OAAO;QACL,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,EAAE;QACX,KAAK,CAAC,SAAS,CAAC,KAAK;YACnB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACxB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC3B,CAAC;QACD,KAAK,CAAC,UAAU,CAAC,KAAK;YACpB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,MAAM,GAAG,YAAY,EAAE;IAC5C,MAAM,QAAQ,GAAuB;QACnC,IAAI,EAAE,YAAY;QAClB,KAAK,CAAC,KAAK;YACT,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,EAAO,EAAE,CAAC;QACrD,CAAC;QACD,KAAK,CAAC,WAAW;YACf,OAAO,IAAI,CAAC;QACd,CAAC;KACF,CAAC;IACF,OAAO,IAAI,iBAAiB,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAC,CAAC;AACtF,CAAC;AAED,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,KAAK,CACV,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,EACtE,iDAAiD,CAClD,CAAC;QACF,MAAM,CAAC,KAAK,CACV,qBAAqB,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EACnF,yDAAyD,CAC1D,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;QAChC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,EAAE;YAC3F,IAAI,EAAE,4CAA4C;YAClD,OAAO,EAAE;gBACP,QAAQ,EAAE,YAAY;gBACtB,UAAU,EAAE,OAAO;gBACnB,QAAQ,EAAE,OAAO;gBACjB,OAAO,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE;aAC1D;SACF,CAAC,CAAC;QAEH,MAAM,CAAC,KAAK,CACV,OAAO,CAAC,eAAe,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EACtF,yDAAyD,CAC1D,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;QAC1E,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;QAEtC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,aAAa,EAAE;YACxD,QAAQ,EAAE,YAAY;YACtB,SAAS,EAAE,cAAc;YACzB,UAAU,EAAE,MAAM;YAClB,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE;gBACP,EAAE,EAAE,OAAO;gBACX,KAAK,EAAE,cAAc;gBACrB,MAAM,EAAE,SAAS;gBACjB,OAAO,EAAE,OAAO;gBAChB,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,wBAAwB,EAAE,cAAc,EAAE,SAAS,EAAE,EAAE;aAClF;SACF,CAAC,CAAC;QAEH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,yDAAyD,CAAC,CAAC;QAChG,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE;YACvD,mBAAmB,CAAC,OAAO,CAAC;SAC7B,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,MAAM,CAAC,SAAS,CAAC,4BAA4B,CAAC,mBAAmB,CAAC,EAAE;YAClE,MAAM,EAAE,YAAY;YACpB,MAAM,EAAE,KAAK;YACb,QAAQ,EAAE,oBAAoB;YAC9B,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE;SAClD,CAAC,CAAC;QACH,MAAM,CAAC,SAAS,CAAC,4BAA4B,CAAC,gCAAgC,CAAC,EAAE;YAC/E,MAAM,EAAE,kBAAkB;YAC1B,MAAM,EAAE,KAAK;YACb,QAAQ,EAAE,oBAAoB;YAC9B,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE;SACvE,CAAC,CAAC;QACH,MAAM,CAAC,SAAS,CAAC,4BAA4B,CAAC,4CAA4C,CAAC,EAAE;YAC3F,MAAM,EAAE,UAAU;YAClB,MAAM,EAAE,KAAK;YACb,QAAQ,EAAE,0BAA0B;YACpC,KAAK,EAAE,EAAE,aAAa,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE;SACzD,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,MAAM,CAAC,SAAS,CACd,iCAAiC,CAC/B,2CAA2C,EAC3C,IAAI,CAAC,SAAS,CAAC;YACb,KAAK,EAAE,cAAc;YACrB,IAAI,EAAE,wBAAwB;SAC/B,CAAC,CACH,EACD;YACE,MAAM,EAAE,aAAa;YACrB,MAAM,EAAE,MAAM;YACd,QAAQ,EAAE,oBAAoB;YAC9B,IAAI,EAAE;gBACJ,OAAO,EAAE,OAAO;gBAChB,MAAM,EAAE,SAAS;gBACjB,KAAK,EAAE,cAAc;gBACrB,IAAI,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,KAAK,EAAE,wBAAwB,EAAE;aACrE;SACF,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,CAAC,SAAS,CACd,iCAAiC,CAC/B,4CAA4C,EAC5C,IAAI,CAAC,SAAS,CAAC;YACb,QAAQ,EAAE,YAAY;YACtB,UAAU,EAAE,MAAM;YAClB,QAAQ,EAAE,OAAO;YACjB,WAAW,EAAE,aAAa;YAC1B,OAAO,EAAE;gBACP,KAAK,EAAE,cAAc;gBACrB,MAAM,EAAE,SAAS;gBACjB,OAAO,EAAE,OAAO;gBAChB,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,IAAI,EAAE;gBAC/D,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,SAAS,EAAE,EAAE;aAC3E;SACF,CAAC,CACH,EACD;YACE,MAAM,EAAE,aAAa;YACrB,MAAM,EAAE,KAAK;YACb,QAAQ,EAAE,0BAA0B;YACpC,IAAI,EAAE;gBACJ,EAAE,EAAE,OAAO;gBACX,MAAM,EAAE,SAAS;gBACjB,KAAK,EAAE,cAAc;gBACrB,IAAI,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,KAAK,EAAE,iBAAiB,EAAE;gBAC7D,OAAO,EAAE,OAAO;gBAChB,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,IAAI,EAAE;aAChE;SACF,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,CAAC,SAAS,CAAC,8BAA8B,CAAC,4CAA4C,CAAC,EAAE;YAC7F,MAAM,EAAE,aAAa;YACrB,MAAM,EAAE,QAAQ;YAChB,QAAQ,EAAE,0BAA0B;SACrC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CACX,GAAG,EAAE,CACH,iCAAiC,CAC/B,8BAA8B,EAC9B,IAAI,CAAC,SAAS,CAAC;YACb,EAAE,EAAE,OAAO;YACX,KAAK,EAAE,cAAc;YACrB,OAAO,EAAE,OAAO;YAChB,IAAI,EAAE,wBAAwB;SAC/B,CAAC,CACH,EACH,kBAAkB,CACnB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index-emission.test.d.ts.map
@@ -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":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=layout-prompt.test.d.ts.map
@@ -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,23 @@
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
+ assert.match(file.content, /by-state/u);
17
+ assert.match(file.content, /by-space/u);
18
+ assert.match(file.content, /by-parent/u);
19
+ assert.match(file.content, /by-key/u);
20
+ assert.match(file.content, /jq /u);
21
+ });
22
+ });
23
+ //# 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;QACrC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACtC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=path-mapper.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-mapper.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/path-mapper.test.ts"],"names":[],"mappings":""}